// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event UIBusinessLogic.GlobalPanelMouseClick(
  IDPanel Panel        // Object that fires this event
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  if (Row > -1)
  {
    UIBusinessLogic.PanelRowButtonRepository.globalPanelMouseClickHandler(Panel, Button, XB, YB, Column)
  }
}


// ──────────────────────────────────

// **************************************************************************************
// Event raised to the form when it is activated, meaning when it is brought to the front
// **************************************************************************************
event UIBusinessLogic.GlobalActivate(
  IDForm Form // Object that fires this event
)
{
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event UIBusinessLogic.GlobalPanelDynamicProperties(
  IDPanel Panel // Object that fires this event
)
{
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private static string AppAiToolUtils.serializeMainModuleCollectionToJson(
  IDCollection results of MainModule // 
)
{
  string result = ""
   
  IDArray jsonArray = new()
   
  for each MainModule mm in results
  {
    IDMap item = new()
    item.setValue("id", mm.getMainID())
    item.setValue("name", mm.getDescription())
    jsonArray.addObject(item)
  }
   
  result = JSON.stringify(jsonArray)
   
  return result
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static string AppAiToolUtils.getModelloRequirements(
  int idTemplateEvento // 
)
{
   
  string stringResult = ""
  //  
  // load modello evento
  ModelloEvento me = null
   
  if (idTemplateEvento > 0)
  {
    me = ModelloEvento.getFromDB(idTemplateEvento, ...)
  }
   
  if (me == null)
  {
    stringResult = formatMessage("{"error":"ModelloEvento with id '|1' not found"}", idTemplateEvento, ...)
  }
  else 
  {
    IDMap result = new()
    result.setValue("id", idTemplateEvento)
    result.setValue("name", me.DESCRTITOLO)
     
    // Cdata Sections
    IDArray cdataSections = new()
    IDCollection sections of CdataSection = me.GetAvailableCustomDataSections(...)
     
    for each CdataSection cs in sections
    {
      IDMap sectionMap = new()
      sectionMap.setValue("sectionName", cs.Name)
       
      IDArray fields = new()
      for each MainModuleDatoPersonalizzatoInfo cfi in cs.CDATAFIELDSINFO
      {
         if (cfi.Active != Yes)
           continue 
          
         IDMap fieldMap = new()
         fieldMap.setValue("id", cfi.IDCDATAFLD)
         fieldMap.setValue("name", cfi.Caption)
         fieldMap.setValue("type", cfi.getCustomDataType())
         fieldMap.setValue("mandatory", if(cfi.Mandatory == Yes, "MANDATORY", "optional"))
          
          
         // combo options
         int cdataType = cfi.getCustomDataType()
         if (cdataType == ComboCDataType)
         {
           CMBValueParser cvp = CMBValueParser.create(cfi.CMBVALUE, ComboCDataType)
           cvp.doParse()
           IDArray options = new()
           for (int i = 0; i < cvp.Elements.length(); i = i + 1)
           {
             string optionName = cvp.ElementsIndex.getValue(i)
             options.addValue(optionName)
           }
           fieldMap.setObject("validValues", options)
         }
          
         fields.addObject(fieldMap)
      }
      sectionMap.setObject("fields", fields)
      cdataSections.addObject(sectionMap)
    }
    result.setObject("cdataSections", cdataSections)
     
    // REFERENCES
    IDArray references = new()
     
    me.loadCollectionFromDB(me.ModelloEventoRiferimenti, ...)
    me.loadCollectionFromDB(me.Riferimenti, ...)
     
    for each ModelloEventoRiferimento mer in me.ModelloEventoRiferimenti
    {
      IDMap refMap = new()
      refMap.setValue("idTipoRiferimento", mer.IDTipoRiferimento)
       
      // load reference type to get name and kordApp
      ReferenceType rt = ReferenceType.get(mer.IDTipoRiferimento)
      refMap.setValue("name", rt.Name)
      refMap.setValue("kordApp", rt.SourceKordapp)
      refMap.setValue("mandatory", if(mer.MANDATORYROWS > 0, "MANDATORY", "optional"))
      refMap.setValue("minRows", mer.MANDATORYROWS)
       
      // check if pre-populated in modello riferimenti
      boolean isPrePopulated = false
      for each Riferimento r in me.Riferimenti
      {
         if (r.IDTipoRiferimento == mer.IDTipoRiferimento)
         {
           isPrePopulated = true
           refMap.setValue("idPrePopulated", r.IDForAll)
           refMap.setValue("namePrePopulated", r.DestinationDescription)
           break 
         }
      }
      refMap.setValue("prePopulated", if(isPrePopulated, "pre-populated", ""))
       
      // reference cdata
      IDMap infoCdataRef = Riferimento.GetInfoCdataRef(mer.IDTipoRiferimento)
      IDArray refCdata = new()
      IDArray keys = infoCdataRef.getKeys()
      for (int i = 0; i < keys.length(); i = i + 1)
      {
         string key = keys.getValue(i)
         IDArray ida = cast(infoCdataRef.getObject(key))
          
         IDMap refCdataField = new()
         refCdataField.setValue("id", ida.getValue(0))
         refCdataField.setValue("name", ida.getValue(1))
         refCdataField.setValue("type", ida.getValue(2))
          
         // combo options for ref cdata
         string cmbValue = ida.getValue(3)
         int refCdataType = toInteger(ida.getValue(2))
         if (nullValue(cmbValue, "") != "" and refCdataType == ComboRefDataType)
         {
           CMBValueParser cvp = CMBValueParser.create(cmbValue, ComboCDataType)
           cvp.doParse()
           IDArray options = new()
           for (int j = 0; j < cvp.Elements.length(); j = j + 1)
           {
             string optionName = cvp.ElementsIndex.getValue(j)
             options.addValue(optionName)
           }
           refCdataField.setObject("validValues", options)
            
         }
         refCdata.addObject(refCdataField)
      }
      refMap.setObject("referenceCdata", refCdata)
       
      references.addObject(refMap)
    }
    result.setObject("references", references)
     
    // AGENT INSTRUCTIONS
    result.setValue("agentInstructions", AppAiToolUtils.buildAgentInstructions())
     
    stringResult = JSON.stringify(result)
  }
   
   
  return stringResult
}


// ──────────────────────────────────

// ***************************************************************************************************************************************************
// returns an hardcoded string used as agent instructions, to improve the human readability of this method, the hardcoded string is written also here:
// 
// To call createEvento build the payload as a JSON string with this structure:
// {
//   'cdata': {
//     '<id>_INFO': '<field name>',
//     '<id>': <value>,
//     ...
//   },
//   'riferimenti': [
//     {
//       'id': <resolved id>,
//       'idTipoRiferimento': <int>,
//       'idTipoRiferimento_INFO': '<ref type name>',
//       'cdata': {
//         '<id>_INFO': '<field name>',
//         '<id>': <value>
//       }
//     }
//   ]
// }
// 
// Rules:
// - _INFO keys are human-readable labels ignored by the parser
// - For combo fields use exactly one of the listed validValues
// - Omit cdata on a reference if it has no cdata fields
// - Skip pre-populated references unless the user wants to override
// - Always resolve IDs via findMainModule before calling createEvento
// 
// Example for modello 170:
// {
//   "cdata": {
//     "28_INFO": "Ore Totali",
//     "28": 4
//   },
//   "riferimenti": [
//     {
//       "id": 333,
//       "idTipoRiferimento": 3,
//       "idTipoRiferimento_INFO": "Partecipanti formazione",
//       "cdata": {
//         "2_INFO": "Tipo Partecipante",
//         "2": "Allievo"
//       }
//     }
//   ]
// }
// ***************************************************************************************************************************************************
private static string AppAiToolUtils.buildAgentInstructions()
{
  string s = "To call createEvento build the payload as a JSON string with this structure: {"cdata":{"<id>_INFO":"<field name>","<id>":<value>,...},"riferimenti":[{"id":<resolved 
           id>,"idTipoRiferimento":<int>,"idTipoRiferimento_INFO":"<ref type name>","cdata":{"<id>_INFO":"<field name>","<id>":<value>}}]}. Rules: _INFO keys are human-readable labels ignored by the parser. For 
           combo fields use exactly one of the listed validValues. Omit cdata on a reference if it has no cdata fields. Skip pre-populated references unless the user wants to override. Always resolve IDs via 
           findMainModule before calling createEvento. Example for modello 170: {"cdata":{"28_INFO":"Ore Totali","28":4},"riferimenti":[{"id":333,"idTipoRiferimento":3,"idTipoRiferimento_INFO":"Partecipanti 
           formazione","cdata":{"2_INFO":"Tipo Partecipante","2":"Allievo"}}]}"
  return s
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static string AppAiToolUtils.createEvento(
  int idTemplateEvento                                        // 
  string payload                                              // 
  Utente utente                                               // 
  optional string:executionModes executionMode = "normalMode" // 
)
{
   
  // PARSE PAYLOAD
  IDMap payloadMap = cast(JSON.parse(payload))
  if (payloadMap == null)
  {
    return "{"error":"Invalid payload JSON"}"
  }
   
  IDMap cdataMap = cast(payloadMap.getObject("cdata"))
  IDArray riferimentiArray = cast(payloadMap.getObject("riferimenti"))
   
  if (cdataMap == null)
    cdataMap = new()
  if (riferimentiArray == null)
    riferimentiArray = new()
   
  // LOAD MODELLO
  ModelloEvento me = null
  if (idTemplateEvento > 0)
  {
    me = ModelloEvento.getFromDB(idTemplateEvento, ...)
  }
   
  if (me == null)
  {
    return formatMessage("{"error":"ModelloEvento with id '|1' not found"}", idTemplateEvento, ...)
  }
   
  me.loadCollectionFromDB(me.ModelloEventoRiferimenti, ...)
  me.loadCollectionFromDB(me.Riferimenti, ...)
   
  // VALIDATE MANDATORY CDATA
  IDCollection sections of CdataSection = me.GetAvailableCustomDataSections(...)
  for each CdataSection cs in sections
  {
    for each MainModuleDatoPersonalizzatoInfo cfi in cs.CDATAFIELDSINFO
    {
      if (cfi.Active != Yes)
         continue 
      if (cfi.Mandatory != Yes)
         continue 
       
      boolean found = false
      IDArray keys = cdataMap.getKeys()
      for (int i = 0; i < keys.length(); i = i + 1)
      {
         string key = keys.getValue(i)
         if (right(key, 5) == "_INFO")
           continue 
         if (toInteger(key) == cfi.IDCDATAFLD)
         {
           found = true
           break 
         }
      }
      if (!(found))
      {
         return formatMessage("{"error":"Mandatory cdata '|1' (ID:|2) not provided"}", cfi.Caption, cfi.IDCDATAFLD, ...)
      }
    }
  }
   
  // VALIDATE MANDATORY REFERENCES
  for each ModelloEventoRiferimento mer in me.ModelloEventoRiferimenti
  {
    if (mer.MANDATORYROWS <= 0)
      continue 
     
    // skip if pre-populated in modello
    boolean isPrePopulated = false
    for each Riferimento r in me.Riferimenti
    {
      if (r.IDTipoRiferimento == mer.IDTipoRiferimento)
      {
         isPrePopulated = true
         break 
      }
    }
    if (isPrePopulated)
      continue 
     
    // count provided in payload
    int countProvided = 0
    for (int i = 0; i < riferimentiArray.length(); i = i + 1)
    {
      IDMap rif = cast(riferimentiArray.getObject(i))
      if (toInteger(rif.getValue("idTipoRiferimento")) == mer.IDTipoRiferimento)
         countProvided = countProvided + 1
    }
     
    ReferenceType rt = ReferenceType.get(mer.IDTipoRiferimento)
    if (countProvided < mer.MANDATORYROWS)
      return formatMessage("{"error":"Reference '|1' is mandatory (min:|2) but not provided"}", rt.Name, mer.MANDATORYROWS, ...)
  }
   
   
  // CREATE EVENTO
  Personale dipendente = utente.getLinkedPersonale()
  int idDipendente = dipendente.IDDIPENDENTE
   
  Evento newEvento = Evento.create(utente.IDUTENTE, idDipendente, idDipendente, idTemplateEvento, ...)
   
  // SET CDATA
  IDCollection eventoSections of CdataSection = newEvento.GetAvailableCustomDataSections(...)
   
  IDArray payloadKeys = cdataMap.getKeys()
  for (int j = 0; j < payloadKeys.length(); j = j + 1)
  {
    string key = payloadKeys.getValue(j)
    if (right(key, 5) == "_INFO")
      continue 
     
    int idCdataFld = toInteger(key)
    string value = cdataMap.getValue(key)
    boolean cdataSet = false
     
    eventoSections.moveFirst()
     
    while (!(cdataSet) and !(eventoSections.isEof()))
    {
      CdataSection cs = cast(eventoSections.getAt())
      for each MainModuleDatoPersonalizzatoInfo cfi in cs.CDATAFIELDSINFO
      {
         if (cfi.IDCDATAFLD == idCdataFld)
         {
           newEvento.setDatoPersonalizzato(value, cfi)
           cdataSet = true
           break 
         }
      }
      eventoSections.moveNext()
    }
  }
   
  // ADD RIFERIMENTI
  for (int k = 0; k < riferimentiArray.length(); k = k + 1)
  {
    IDMap rif = cast(riferimentiArray.getObject(k))
    int idForAll = toInteger(rif.getValue("id"))
    int idTipoRiferimento = toInteger(rif.getValue("idTipoRiferimento"))
     
    Riferimento newRif = Riferimento.create(idTipoRiferimento, newEvento.IDEVENTO, idForAll, ...)
     
    // set ref cdata
    IDMap rifCdata = cast(rif.getObject("cdata"))
    if (rifCdata != null)
    {
      IDArray rifCdataKeys = rifCdata.getKeys()
      for (int i = 0; i < rifCdataKeys.length(); i = i + 1)
      {
         string key = rifCdataKeys.getValue(i)
         if (right(key, 5) == "_INFO")
           continue 
          
         int idRefCdata = toInteger(key)
         string value = rifCdata.getValue(key)
          
         RiferimentoDatoPersonalizzatoInfo rdpi = RiferimentoDatoPersonalizzatoInfo.get(idRefCdata)
         newRif.setRDatoPersonalizzato(rdpi, value)
      }
    }
     
    newEvento.Riferimenti.add(newRif)
  }
   
  // SAVE
   
  boolean validEvento = newEvento.validate(...)
  string errorInfo = ""
  if (!(validEvento))
  {
     
    // retrive errors as string so agent can read them
    errorInfo = ErrorReporter.GetDIVForErrorDisplayForSingleDocument(newEvento)
    return formatMessage("{"error":"Evento validation failed, impossible to save, details: |1"}", errorInfo, ...)
  }
  else 
  {
    if (executionMode == normalMode)
    {
      newEvento.saveToDB(...)
    }
  }
   
  IDMap successResult = new()
  successResult.setValue("status", "ok")
  successResult.setValue("idEvento", newEvento.IDEVENTO)
  successResult.setValue("descrizione", newEvento.DESCRTITOLO)
   
  return JSON.stringify(successResult)
}


// ──────────────────────────────────

// ********************************************************************************
// Returns all requirements for creating an event of the given template, including:
// mandatory and optional cdata fields (with valid values for combo fields),
// mandatory and optional references (with their cdata fields),
// pre-populated references inherited from the template,
// and instructions on how to build the payload for createEvento.
// Always call this before createEvento to know what data to collect from the user.
// ********************************************************************************
public string EventoCreatorTool.getModelloRequirements(
  int idTemplateEvento // ID of the ModelloEvento (event template) to inspect
)
{
  return AppAiToolUtils.getModelloRequirements(idTemplateEvento)
}


// ──────────────────────────────────

// *****************************************************************************************************************
// Creates a new event using the given template and the data collected from the user.
// Returns {"status":"ok","idEvento":123,"descrizione":"..."} on success.
// Returns {"error":"..."} on failure with a human-readable explanation of what is missing or invalid,
// so the agent can ask the user for the missing data and retry.
// Build the payload JSON following the agentInstructions returned by getModelloRequirements.
// 
// Example of a valid payload for ModelloEvento 170 (Formazione Iniziale Generale Sicurezza):
// {
//   "cdata": {
//     "28_INFO": "Ore Totali",
//     "28": 4
//   },
//   "riferimenti": [
//     {
//       "id": 333,
//       "idTipoRiferimento": 3,
//       "idTipoRiferimento_INFO": "Partecipanti formazione",
//       "cdata": {
//         "2_INFO": "Tipo Partecipante",
//         "2": "Allievo"
//       }
//     }
//   ]
// }
// Notes:
// - _INFO keys are human-readable labels, ignored by the parser
// - reference IDs must be resolved via findMainModule before calling createEvento
// - pre-populated references (e.g. Titolo Formativo) are inherited from the template and do not need to be provided
// *****************************************************************************************************************
public string EventoCreatorTool.createEvento(
  int idTemplateEvento // ID of the ModelloEvento (event template) to use
  string payload       // JSON string with cdata and riferimenti — see agentInstructions from getModelloRequirements
  Utente utente        // The user on whose behalf the event is created (tipically QappCore.LoggedUser can be used)
)
{
  return AppAiToolUtils.createEvento(idTemplateEvento, payload, utente, normalMode)
}


// ──────────────────────────────────

// ********************************************************************************************
// Searches for entities (customers, people, projects, etc.) by name and returns a JSON array
// of matches with their IDs and names: [{"id":123,"name":"Acme Srl"}, ...].
// Always call this to resolve a name typed by the user into an ID before calling createEvento.
// Show results to the user and ask for confirmation if the match is not exact.
// Returns [] if nothing is found.
// ********************************************************************************************
public string EventoCreatorTool.findMainModule(
  string query        //  Name or partial name to search for (case-insensitive)
  int:kordapp kordapp // Type of entity to search: Personale, ClientiFornitori, AltreAnagrafiche, Progetti, etc.
)
{
  return AppAiToolUtils.findMainModule(query, kordapp, normalMode)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AppAiToolsTester.ButtontestModelloRequirements()
{
  EventoCreatorTool ect = new()
  string s = ect.getModelloRequirements(NewPanel.idmodelloeventoNewPanel)
  NewPanel.responseNewPanel = s
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AppAiToolsTester.Buttontestfindmain()
{
  EventoCreatorTool ect = new()
  string mmCollectionAsJson = ect.findMainModule(toString(NewPanel.Query), NewPanel.kordapp)
   
  NewPanel.foundmainmodule = mmCollectionAsJson
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AppAiToolsTester.Buttoncreateevento()
{
  EventoCreatorTool ect = new()
   
  string s = ect.createEvento(NewPanel.idmodelloeventoNewPanel, NewPanel.PayloadForEventoCreationNewPanel, QappCore.Loggeduser)
  UIBusinessLogic.messageBox(s)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AppAiToolsTester.Buttongetpayload()
{
  NewPanel.PayloadForEventoCreationNewPanel = "{"cdata": {"2038_INFO": "Caratteristiche formazione","2038": "In aula","28_INFO": "Ore Totali","28": 8,"68_INFO": "Modalità verifica efficacia","68": "Test 
           finale"},"riferimenti": []}"
}


// ──────────────────────────────────

// **********************************************************
// this payload is passed (human readable version)
// 
// {
//   "cdata": {
//     "2038_INFO": "Caratteristiche formazione",
//     "2038": "In aula",
//     "28_INFO": "Ore Totali",
//     "28": 8,
//     "68_INFO": "Modalità verifica efficacia",
//     "68": "Test finale"
//   },
//   "riferimenti": [
//     {
//       "id": 166, -- CHANGE ID_DIPENDENTE!
//       "idTipoRiferimento": 3,
//       "idTipoRiferimento_INFO": "Partecipanti formazione",
//       "cdata": {
//         "2_INFO": "Tipo Partecipante",
//         "2": "Docente",
//         "3_INFO": "Ore Presenza",
//         "3": 6,
//         "1743_INFO": "misura scarpe",
//         "1743": 41
//       }
//     },
//     {
//       "id": 19, -- CHANGE ID_DIPENDENTE!
//       "idTipoRiferimento": 3,
//       "idTipoRiferimento_INFO": "Partecipanti formazione",
//       "cdata": {
//         "2_INFO": "Tipo Partecipante",
//         "2": "Allievo",
//         "3_INFO": "Ore Presenza",
//         "3": 8,
//         "1743_INFO": "misura scarpe",
//         "1743": 43
//       }
//     },
//     {
//       "id": 25, -- CHANGE ID_DIPENDENTE!
//       "idTipoRiferimento": 3,
//       "idTipoRiferimento_INFO": "Partecipanti formazione",
//       "cdata": {
//         "2_INFO": "Tipo Partecipante",
//         "2": "Tutor",
//         "3_INFO": "Ore Presenza",
//         "3": 4,
//         "1743_INFO": "misura scarpe",
//         "1743": 39
//       }
//     }
//   ]
// }
// **********************************************************
public void AppAiToolsTester.Buttongetpayloadwith()
{
  NewPanel.PayloadForEventoCreationNewPanel = "{"cdata":{"2038_INFO":"Caratteristiche formazione","2038":"In aula","28_INFO":"Ore Totali","28":8,"68_INFO":"Modalità verifica efficacia","68":"Test 
           finale"},"riferimenti":[{"id":166,"idTipoRiferimento":3,"idTipoRiferimento_INFO":"Partecipanti formazione","cdata":{"2_INFO":"Tipo Partecipante","2":"Docente","3_INFO":"Ore Presenza","3":6,"1743_INFO­
           ":"misura scarpe","1743":41}},{"id":19,"idTipoRiferimento":3,"idTipoRiferimento_INFO":"Partecipanti formazione","cdata":{"2_INFO":"Tipo Partecipante","2":"Allievo","3_INFO":"Ore 
           Presenza","3":8,"1743_INFO":"misura scarpe","1743":43}},{"id":25,"idTipoRiferimento":3,"idTipoRiferimento_INFO":"Partecipanti formazione","cdata":{"2_INFO":"Tipo 
           Partecipante","2":"Tutor","3_INFO":"Ore Presenza","3":4,"1743_INFO":"misura scarpe","1743":39}}]}"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AppAiToolsTester.clear()
{
  delete from NewPanel
}


// ──────────────────────────────────

// **********************************************************************************************************************************
// this procedure returns a collection of scheduler events generated from the Calendar Impegni created in QappCore (Calendar Manager)
// **********************************************************************************************************************************
public IDCollection QualibusSchedulerController.getEvents(
  optional boolean loadData = -1 // 
)
{
  if (loadData)
  {
    this.computeEvents()
  }
  return SchedulerEvents
}


// ──────────────────────────────────

// ********************************************************************************************
// this costructor prepare a well created instance of QualibusScheulderController. 
// It sets its main properties and computes: 
// - CalendarManagers (responsables to load the events)
// - the property SchedulerConfiguration (needed to initialize correctly the dxScheduler below)
// ********************************************************************************************
public static QualibusSchedulerController QualibusSchedulerController.create(
  IDCollection users of Utente // 
  date time from               // 
  date time to                 // 
)
{
  QualibusSchedulerController controller = new()
  controller.From = from
  controller.To = to
  controller.computeCalendarManager(users)
  controller.prepareConfiguration(users)
  return controller
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void QualibusSchedulerController.prepareConfiguration(
  IDCollection users of Utente // 
)
{
  IDArray resources = this.computeResources(users)
  IDMap editing = new()
  editing.setValue("allowAdding", false)
  editing.setValue("allowDeleteting", false)
  editing.setValue("allowDragging", false)
  editing.setValue("allowResizing", false)
  editing.setValue("allowTimeZoneEditing", false)
  editing.setValue("allowUpdating", false)
   
  IDArray supportedViews = new()
  supportedViews.setValue(0, "day")
  supportedViews.setValue(1, "week")
  supportedViews.setValue(2, "workWeek")
  supportedViews.setValue(3, "month")
  supportedViews.setValue(4, "agenda")
   
  Configuration = SchedulerConfiguration.Create(..., editing, 60, 1, 5, 19, supportedViews, workweek, now(), resources)
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************************************
// this procedure prepares the resources to be set in the scheduler
// ****************************************************************
public IDArray QualibusSchedulerController.computeResources(
  IDCollection users of Utente // 
)
{
  IDArray resultingResources = new()
  int counter = 1
  for each Utente user in users
  {
    string image = null
    string resourceName = ""
    Personale p = user.getLinkedPersonale()
    if (p)
    {
      resourceName = p.FullName
      string filename = toString(p.IDDIPENDENTE) + "resource.jpg"
      if (p.FOTO != null)
      {
         string blobFilePath = saveBlobFile(p.FOTO, UIBusinessLogic.tempPath, filename)
         image = "temp/" + filename
      }
    }
    else 
    {
      resourceName = user.Username
    }
    SchedulerResource resource = SchedulerResource.create(counter, resourceName, "Utente", image)
    resultingResources.setObject(resultingResources.length(), resource)
     
    counter = counter + 1
     
    // TO BE SAVED
     
  }
  return resultingResources
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void QualibusSchedulerController.computeCalendarManager(
  IDCollection users of Utente // 
)
{
  CalendarManagers.clear()
  int currentResourceID = 1
  for each Utente u in users
  {
    CalendarManager cManager = CalendarManager.create(currentResourceID, u, From, To)
    CalendarManagers.add(cManager)
    currentResourceID = currentResourceID + 1
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void QualibusSchedulerController.computeEvents()
{
  SchedulerEvents.clear()
   
  for each CalendarManager cm in CalendarManagers
  {
    int currentResourceID = cm.ID
    IDCollection calendarImpegno of CalendarImpegno = cm.getAllImpegni(...)
    IDMap alreadyUsedIDs = new()
    for each CalendarImpegno ci in calendarImpegno
    {
      string schedulerEventID = this.generateUniqueGuidPart(alreadyUsedIDs, 50)
      switch (ci.typeName())
      {
         case AttivitaCalendar.className(...):
           AttivitaCalendar ac = cast(ci)
           string attivitaID = toString(ac.Attivita.IDATTIVITA)
           schedulerEventID = SH.Concat(schedulerEventID, attivitaID, "_")
           Attività attivita = ac.Attivita
           string image = if(attivita.PROGRAMMATA == Yes, "images/activity_todo.png", "images/activity_closed.png")
           SchedulerEvent event = SchedulerEvent.create(ci.Description, currentResourceID, ci.Start, ci.End, "Attività", schedulerEventID, ci.Description, image, false, "#81AFB6", false)
           SchedulerEvents.add(event)
         break
         case DisposizioneCalendar.className(...):
           DisposizioneCalendar dc = cast(ci)
           string dispId = toString(dc.Disposizione.IDATTIVITA)
           schedulerEventID = SH.Concat(schedulerEventID, dispId, "_")
           string image = if(dc.Disposizione.isClosed(), "images/disposizioni_closed.png", "images/disposizioni_todo.png")
           SchedulerEvent event = SchedulerEvent.create(ci.Description, currentResourceID, dc.Start, dc.End, "Disposizione", schedulerEventID, dc.Description, image, false, "#41B6D4", false)
           SchedulerEvents.add(event)
         break
         case PromemoriaCalendar.className(...):
           PromemoriaCalendar proC = cast(ci)
           string procID = toString(proC.Promemoria.IDPROMEMORIA)
           schedulerEventID = SH.Concat(schedulerEventID, procID, "_")
           string image = if(proC.Promemoria.DATACHIUSURA == null, "images/promemoria_todo.png", "images/promemoria_closed.png")
           SchedulerEvent event = SchedulerEvent.create(ci.Description, currentResourceID, proC.Start, proC.End, "Promemoria", schedulerEventID, proC.Description, image, false, "#648649", false)
           SchedulerEvents.add(event)
         break
         case MemoCalendar.className(...):
           MemoCalendar memoCalendar = cast(ci)
           string memoID = toString(memoCalendar.Memo.IDPROMEMORIA)
           schedulerEventID = SH.Concat(schedulerEventID, memoID, "_")
           SchedulerEvent event = SchedulerEvent.create(memoCalendar.Description, currentResourceID, memoCalendar.Start, memoCalendar.End, "Memo", schedulerEventID, memoCalendar.Description, "images/memo.png"
                    , false, "#B4AEAE", false)
           SchedulerEvents.add(event)
         break
      }
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void QualibusSchedulerController.updateConfigurationsForNewUsers(
  IDCollection users of Utente // 
)
{
  this.computeCalendarManager(users)
  this.prepareConfiguration(users)
}


// ──────────────────────────────────

// ****************************************************************************************************************************************************************************************************************
// WHAT: this procedure generates a string of 4 characters taken by a random guid. 
// HOW: It checks that the string is not contained in the Map AlreadyUsed, if that is the case, the while loop is meant to avoid duplicates, trying to generate another guid that is not contained in the previous
// map.
// this process goes on for maximum "maxAttempts" attempts, after that amount of tests it return what it has.
// WHY: The reason to generate unique alpha numeric strings is to have ids that are unique, so to add Events into dxScheduler with unique ids
// ****************************************************************************************************************************************************************************************************************
public string QualibusSchedulerController.generateUniqueGuidPart(
  IDMap alreadyUsed              // 
  optional int maxAttempts = 500 // 
)
{
  string guidPart = left(docIDToGuid(newDocID()), 4)
  int loopChecker = 0
  while (alreadyUsed.containsKey(guidPart))
  {
    guidPart = left(docIDToGuid(newDocID()), 4)
    loopChecker = loopChecker + 1
    if (loopChecker == maxAttempts)
    {
      break 
    }
  }
  alreadyUsed.setValue(guidPart, true)
  return guidPart
}


// ──────────────────────────────────

// **********************************************************************
// An event fired by the application when a command is passed via the URL
// **********************************************************************
event UIBusinessLogic.OnCommand(
  string Command // It is a string containing the value of the URL parameter named CMD
)
{
   
  // MULTI_UPLOAD_COMPLETED comes from a js customization, it is meant to mark the moment in which multi upload has been completed, as an additional info it contains also the files count, we check for it >=1
  // just for safety
  if (Command == "MULTI_UPLOAD_COMPLETED")
  {
    int uploadedFilesCount = toInteger(UIBusinessLogic.getURLParam("FILES_COUNT"))
     
    if (uploadedFilesCount >= 1)
    {
      UIBusinessLogic.UIBusinessLogicCommunication.notifyUploadCompleted()
    }
  }
   
  if (Command == "AITEST")
  {
    AppAiToolsTester.show(...)
  }
}


// ──────────────────────────────────

// ********************************************************
// An event fired by the application when it is initialized
// ********************************************************
event UIBusinessLogic.Initialize()
{
  UIBusinessLogic.initializeGlobalVariables()
}


// ──────────────────────────────────

// *************************************************************************************************************************************************
// Event raised to the application or to a component when something, an application or component, has sent a message using the SendAppMessage method
// *************************************************************************************************************************************************
event UIBusinessLogic.OnAppMessage(
  string Message   // Name of the message
  object Parameter // An object-type parameter that contains the information about the message sent. This parameter is the one provided to the SendAppMessage method
)
{
  if (Message == "MESSAGEBOX")
  {
    IDArray arryHavingErrorMsg = cast(Parameter)
    string errorMessage = Tools.ArrayToString(arryHavingErrorMsg, ...)
    UIBusinessLogic.messageBox(errorMessage)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UIBusinessLogicCommunication.SetFileUploadMode(
  string:documentUploadModes uploadMode // 
)
{
  FileUploaderHandler.setMode(uploadMode)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDArray UIBusinessLogicCommunication.GetUploadedFilesArray()
{
  return FileUploaderHandler.getFiles(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static UIBusinessLogicCommunication UIBusinessLogicCommunication.create()
{
  UIBusinessLogicCommunication uiblc = new()
  uiblc.init()
  return uiblc
}


// ──────────────────────────────────

// *********************************************
// Raised when the document is being initialized
// *********************************************
event UIBusinessLogicCommunication.OnInit()
{
  FileUploaderHandler = FileUploaderHandler.create()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public FileUploaderHandler UIBusinessLogicCommunication.getFileUploaderHandler()
{
  return FileUploaderHandler
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UIBusinessLogicCommunication.notifyUploadCompleted()
{
  FileUploaderHandler.notifyCallerForm()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static IDCollection ErrorReporter.collectErrors(
  IDDocument document               // 
  IDCollection errors of IDDocument // 
)
{
  if (errors == null)
  {
    errors = new()
  }
  UIBusinessLogic.DTTLogMessage(document.typeName(), 46464646, ...)
  errors = this.collectDocumentErrors(document, errors)
   
  // special case for errors within validation at cdataHelper class, associated with MainModule as Object tag
   
  if (MainModule.isMyInstance(document) or Riferimento.isMyInstance(document))
  {
    IDatoPersonalizzatoOwner owner = cast(document)
    if (owner)
    {
      RenderingHelper crh = cast(owner.getRenderingHelper())
      if (crh)
         ErrorReporter.collectErrors(crh, errors)
    }
  }
   
   
  IDDocumentStructure idds = document.getStructure()
  for (int k = 1; k <= idds.getCollectionCount(); k = k + 1)
  {
    IDCollection childColl of IDDocument = (IDCollection)document.getCollection(k)
    for each IDDocument childDoc in childColl
    {
      ErrorReporter.collectErrors(childDoc, errors)
    }
  }
   
  return errors
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static IDCollection ErrorReporter.collectDocumentErrors(
  IDDocument document               // 
  IDCollection errors of IDDocument // 
)
{
  if (errors == null)
  {
    errors = new()
  }
  IDDocumentStructure idds = document.getStructure()
  if (document.isInError(...))
  {
    string recordSpecificInfo = ""
    string riga = ""
     
    // get row number of the error
    IDCollection parentCollection of IDDocument = (IDCollection)document.parentCollection()
    if (parentCollection)
    {
      int rowPos = parentCollection.findDocument(document)
      if (rowPos == 0)
         riga = ""
      else 
         riga = "Riga " + toString(rowPos)
    }
    UIBusinessLogic.DTTLogMessage(formatMessage("property count: |1", idds.getPropertyCount(), ...), ...)
    for (int n = 0; n < idds.getPropertyCount(); n = n + 1)
    {
      if (document.getPropertyError(n) != "")
      {
         IDPropertyDefinition idpd = idds.getPropertyDefinition(n)
         if (idpd)
         {
           UIBusinessLogic.DTTLogMessage(formatMessage("DBCode: |1", idpd.DBCode, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("Tag: |1", idpd.tag, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("Concept: |1", idpd.concept, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("UIName: |1", idpd.UIName, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("Classname: |1", document.className(...), ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("Typename: |1", document.typeName(), ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("FK: |1", idpd.FK, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("DataType: |1", idpd.dataType, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("dataTypeName: |1", idpd.dataTypeName, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("PK: |1", idpd.PK, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("counter: |1", idpd.counter, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("description: |1", idpd.description, ...), 45454545, ...)
           UIBusinessLogic.DTTLogMessage(formatMessage("describeRow: |1", idpd.describeRow, ...), 45454545, ...)
            
           string UIName = idpd.UIName
           if (RenderingHelper.isMyInstance(document))
           {
             RenderingHelper rh = (RenderingHelper)document
             string fieldCode = idpd.tag
             DatoPersonalizzatoInfo dpi = (DatoPersonalizzatoInfo)rh.CdataMapping.getObject(fieldCode)
             if (dpi)
             {
                UIName = dpi.getCaption()
             }
           }
           recordSpecificInfo = SH.Concat(riga, UIName, ...)
         }
         else 
           recordSpecificInfo = riga
          
         ErrorReporter em = ErrorReporter.create(document, recordSpecificInfo, document.getPropertyError(n))
         if (!(this.sameErrorAlreadyExistsInErrorCollection(errors, em)))
         {
           errors.add(em)
         }
      }
    }
     
  }
   
  return errors
}


// ──────────────────────────────────

public static ErrorReporter ErrorReporter.create(
  IDDocument doc      // 
  string specificInfo // 
  string errorMsg     // 
)
{
  ErrorReporter em = new()
  em.init()
  em.Document = (IDDocument)doc
  em.Area = doc.typeName()
  em.ErrorMessage = errorMsg
  em.RecordSpecificInfo = specificInfo
  return em
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static boolean ErrorReporter.sameErrorAlreadyExistsInErrorCollection(
  IDCollection errors of ErrorReporter // 
  ErrorReporter ErrorReporter          // 
)
{
  boolean errorAlreadyExists = false
  for each ErrorReporter em in errors
  {
    if ((em.ErrorMessage == ErrorReporter.ErrorMessage) and (em.Area == ErrorReporter.Area) and (em.RecordSpecificInfo == ErrorReporter.RecordSpecificInfo))
    {
      errorAlreadyExists = true
      break 
    }
  }
   
  return errorAlreadyExists
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static void ErrorReporter.ShowDocumentErrors(
  IDDocument document // Write a comment for this parameter or press backspace to delete this comment
)
{
  string concatenatedErrorMessages = this.GetDIVForErrorDisplayForSingleDocument(document)
  string tooltipHTMLTitle = "<div class='errorMessageTitle'><h4>Messaggi di errore</h4></div>"
   
  UIBusinessLogic.showTooltip(concatenatedErrorMessages, tooltipHTMLTitle, ..., 65, 15, Right, 0, 10000000, 700)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ErrorReporter.populateHardcodedMap()
{
  ClassNameToTabNameIdMap = new()
  ClassNameToTabNameIdMap.setValue(MainModuleDatoPersonalizzato.className(...), "Dati personalizzati")
  ClassNameToTabNameIdMap.setValue(MainModuleCdataRenderingHelper.className(...), "Dati personalizzati")
  ClassNameToTabNameIdMap.setValue(Clifor.className(...), "Anagrafica")
  ClassNameToTabNameIdMap.setValue(Personale.className(...), "Anagrafica")
  ClassNameToTabNameIdMap.setValue(Evento.className(...), "Anagrafica")
  ClassNameToTabNameIdMap.setValue(ModelloEvento.className(...), "Definizione")
  ClassNameToTabNameIdMap.setValue(ModelloEventoDisposizione.className(...), "Disposizioni")
  ClassNameToTabNameIdMap.setValue(EventiCosto.className(...), "Costi")
  ClassNameToTabNameIdMap.setValue(DOCTIPITAG.className(...), "Tag")
  ClassNameToTabNameIdMap.setValue(DOCTIPISUPPORTO.className(...), "Tipi supporto")
  ClassNameToTabNameIdMap.setValue(DocUbicazioni.className(...), "Ubicazioni")
  ClassNameToTabNameIdMap.setValue(DOCTIPIDOCUMENTO.className(...), "Tipi documento")
  ClassNameToTabNameIdMap.setValue(DOCPARAMETRI.className(...), "Parametri documenti")
  ClassNameToTabNameIdMap.setValue(DocTipiFile.className(...), "Tipi file gestiti")
  ClassNameToTabNameIdMap.setValue(RiferimentoRenderingHelper.className(...), "Riferimenti")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string ErrorReporter.getTabName()
{
  string tabName = ClassNameToTabNameIdMap.getValue(Area)
  if (tabName == "")
  {
    // Class ClassNameToTabNameIdMap does not have special configuration for "Document" to report
    // we refer to Class.UI Name
    IDDocumentStructure idds = Document.getStructure()
    tabName = idds.UIName
  }
  if (RiferimentoRenderingHelper.isMyInstance(Document))
  {
    RiferimentoRenderingHelper rrh = (RiferimentoRenderingHelper)Document
    tabName = formatMessage("|1 (|2)", tabName, rrh.getReferenceTypeString(), ...)
  }
  return tabName
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static string ErrorReporter.GetDIVForErrorDisplayForSingleDocument(
  IDDocument document // 
)
{
  IDCollection errors of ErrorReporter = new()
  errors = this.collectErrors(document, errors)
  string DIVforErrorDisplay = this.getDIVForErrorDisplay(errors)
   
  return DIVforErrorDisplay
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static void ErrorReporter.showErrorsOfDocumentCollection(
  IDCollection documents of IDDocument // 
)
{
  string panelConcatenatedErrors = this.getDIVForErrorDisplayForADocumentCollection(documents)
   
  string tooltipHTMLTitle = "<div class='errorMessageTitle'><h4>Messaggi di errore</h4></div>"
   
  UIBusinessLogic.showTooltip(panelConcatenatedErrors, tooltipHTMLTitle, ..., 65, 15, Right, 0, 10000000, 700)
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static string ErrorReporter.getDIVForErrorDisplayForADocumentCollection(
  IDCollection documents of IDDocument // 
)
{
  IDCollection errors of ErrorReporter = new()
  for each IDDocument doc in documents
  {
    errors = this.collectErrors(doc, errors)
  }
   
  string DIVforErrorDisplay = this.getDIVForErrorDisplay(errors)
  return DIVforErrorDisplay
}


// ──────────────────────────────────

// **************************************************************************************
// concatenates all the errors and preapres a div that the UI will show as error messages
// **************************************************************************************
private static string ErrorReporter.getDIVForErrorDisplay(
  IDCollection errors of ErrorReporter // 
)
{
  string concatenatedErrorMessage = ""
  for each ErrorReporter er in errors
  {
    string tabName = er.getTabName()
    concatenatedErrorMessage = formatMessage("|1 <br> <div class="errorName"><strong>|2</strong> - |3</div> <div class="errorDetails">|4</div>", concatenatedErrorMessage, tabName, er.RecordSpecificInfo, er.
             ErrorMessage, ...)
  }
  return concatenatedErrorMessage
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static MainModuleFormHelper MainModuleFormHelper.create(
  MainModule mainModule     // 
  IDForm tabbedViewSubform  // 
  IDForm mainModuleMainForm // 
)
{
  MainModuleFormHelper mmh = new()
  mmh.init()
  mmh.Mainmodule = mainModule
  mmh.TabbedViewSubform = tabbedViewSubform
  mmh.MainModuleUILogic = MainModuleUILogic.create(mainModule)
  mmh.MainForm = mainModuleMainForm
   
  // wire MainFormReference on the tabbed view
  CommonMainModuleTabbedView cmmtv = cast(tabbedViewSubform)
  if (cmmtv)
  {
    cmmtv.MainModuleDetailForm = mainModuleMainForm
  }
   
  return mmh
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MainModuleFormHelper.performRefresh()
{
  CommonMainModuleTabbedView cmmtv = null // get the current focused form
  try 
  {
    cmmtv = cast(TabbedViewSubform)
    FocusedForm = cmmtv.GetCurrentlyFocusedForm()
  }
   
  // Reload data: Mainmodule is mutated in-place; subforms see refreshed value 
  // via their panel bindings and via the re-LOAD triggered inside applyTabConfigDelta.
  this.reloadMainModuleFromDatabase()
   
  // Apply tab visibility delta against the freshly evaluated filtered config
  // (e.g., opzioniCliFor changes affect tab visibility). Existing subforms are
  // kept in their slot; new tabs get fresh instances; vanished tabs are hidden.
  if (cmmtv != null and MainModuleUILogic != null)
  {
    cmmtv.applyTabConfigDelta(MainModuleUILogic)
  }
   
  UIBusinessLogic.messageBox("Dati ricaricati")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void MainModuleFormHelper.reloadMainModuleFromDatabase()
{
  Mainmodule.loaded = false
   
   
  DevTools.ToBeReviewed("This code must be reviewed in a team session")
   
  Mainmodule.Promemoria.loaded = false
  Mainmodule.Riferimenti.loaded = false
  Mainmodule.CdataSnapshot.clear()
  Mainmodule.DocCollegati.loaded = false
  Mainmodule.ModuleDocuments.loaded = false
   
  // temporary solution to avoid errors on forcing refresh
  int:kordapp kordapp = Mainmodule.getKordApp()
   
  switch (kordapp)
  {
    case ClientiFornitori:
      Clifor currentClifor = cast(Mainmodule)
      currentClifor.Addresses.loaded = false
      currentClifor.Contacts.loaded = false
      currentClifor.GCFCARATTERIZZAZIONI.loaded = false
      currentClifor.GCFDOCUMENTI.loaded = false
    break
    case Personale:
      Personale p = cast(Mainmodule)
      p.PERCARRIERE.loaded = false
      p.PERCARATTERIZZAZIONI.loaded = false
      p.MSQPERSFUNZIONI.loaded = false
       
    break
    case Funzioni:
      Funzione funzione = cast(Mainmodule)
      funzione.DatiPersonalizzati.loaded = false
      funzione.FUNDOCUMENTI.loaded = false
      funzione.MSQPERSFUNZIONI.loaded = false
      funzione.ModuleDocuments.loaded = false
    break
    case ModelliEventi:
      ModelloEvento me = cast(Mainmodule)
      me.ModelloEventoRiferimenti.loaded = false
      me.ModelloEventoCDSections.loaded = false
      me.Costi.loaded = false
      me.DisposizioniModello.loaded = false
      me.ModuleDocuments.loaded = false
    break
    case Eventi:
      Evento e = cast(Mainmodule)
      e.DatiPersonalizzati.loaded = false
      e.EventiCosti.loaded = false
      e.ModuleDocuments.loaded = false
      e.Disposizioni.loaded = false
    break
    default:
      UIBusinessLogic.DTTLogMessage("Not implemented", ..., DTTError)
    break
  }
   
  Mainmodule.loadFromDB(...)
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void MainModuleFormHelper.deleteTabbedViewPages()
{
  TabbedViewSubform.sendMessage("DELETE_PAGES", ...)
}


// ──────────────────────────────────

// *********************************************************************************************************
// creeates and attaches, using polimorphism inside, the tabbed view subforms to the main module tabbed view
// *********************************************************************************************************
public void MainModuleFormHelper.initializeAllTabbedViewSubForms()
{
   
  CommonMainModuleTabbedView cmmtv = cast(TabbedViewSubform)
  FocusedForm = cmmtv.GetCurrentlyFocusedForm()
   
  if (FocusedForm == null)
  {
    FocusedForm = MainModuleUILogic.getSubformToBeFocused()
  }
   
  SubForms = MainModuleUILogic.getSubformsArray()
  this.attachAllSubforms()
   
  // Eager LOAD for subforms with LoadInitially=true. Other subforms stay lazy
  // and receive LOAD on first ChangePage. Required for setLabelSubForm-hosted
  // subforms to be renderable by the client (empty subforms in a Tab Slot break
  // the client widget initialization).
  this.loadSubformsThatMustBeInitiallyLoaded()
   
  if (Mainmodule.isLocked())
  {
    TabbedViewSubform.sendMessage("MAIN_MODULE_IS_CLOSED", ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void MainModuleFormHelper.attachAllSubforms()
{
  // attaching of subforms
  IDDocument sendMessageData = new()
  sendMessageData.setObjectTag("idFormArray", SubForms)
  sendMessageData.setObjectTag("mainModule", Mainmodule)
   
  IDDocument focusedIdFormInfoTempDoc = new()
  TabbedViewSubform.sendMessage("GET_FOCUSED_ID_FORM", focusedIdFormInfoTempDoc, ...)
  IDForm idFormToBeFocused = (IDForm)focusedIdFormInfoTempDoc.getObjectTag("focusedIdForm")
  if (!(idFormToBeFocused))
  {
    idFormToBeFocused = FocusedForm
  }
  else 
  {
    FocusedForm = idFormToBeFocused
  }
  sendMessageData.setObjectTag("idFormToBeFocused", idFormToBeFocused)
   
  TabbedViewSubform.sendMessage("ATTACH_MULTIPLE_SUBFORMS", sendMessageData, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void MainModuleFormHelper.loadSubformsThatMustBeInitiallyLoaded()
{
  IDArray subformsToBeInitallyLoaded = MainModuleUILogic.getSubformToBeInitallyLoaded()
   
  if (subformsToBeInitallyLoaded == null)
    return 
   
  for (int i = 0; i < subformsToBeInitallyLoaded.length(); i = i + 1)
  {
    IDDocument documentDetailContainer = new()
     
    IDForm currentSubform = (IDForm)subformsToBeInitallyLoaded.getObject(i)
    documentDetailContainer.setObjectTag("subform", currentSubform)
     
    UIBusinessLogic.DTTLogMessage(formatMessage("sending LOAD to subform |1", currentSubform.className(), ...), ..., DTTInfo)
    TabbedViewSubform.sendMessage("LOAD", documentDetailContainer, ...)
  }
}


// ──────────────────────────────────

// *******************************************************************************
// Displays validation errors for the form. When the MainModule fails to save
// because of validation errors, this method is responsible for surfacing them
// to the user: a tooltip with the full error list, plus visual cues (red borders)
// on the offending CustomData fields. The CustomData subform is force-LOADed
// first to make sure its mandatory-field validation has run and has registered
// its errors on MainModule's properties — otherwise, with lazy LOAD, the
// tooltip would render empty.
// *******************************************************************************
public void MainModuleFormHelper.handleErrorDisplay()
{
   
   
  // Force LOAD on CustomData before collecting errors: with lazy LOAD the rendering helper may not exist yet, so its mandatory-field validation has never registered errors on MainModule's properties —
  // ShowDocumentErrors would then return an empty body and the tooltip would render with no message.
  IDForm customDataSubform = this.getCustomDataSubform()
  if (customDataSubform)
  {
    CommonMainModuleTabbedView cmmtv = cast(TabbedViewSubform)
    if (cmmtv != null)
    {
      cmmtv.loadSubform(customDataSubform)
    }
    customDataSubform.sendMessage("SHOWERRORS", ...)
  }
   
  // call the centralized error collector and displayer
  ErrorReporter.ShowDocumentErrors(Mainmodule)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm MainModuleFormHelper.getCustomDataSubform()
{
  IDForm customDataSubform = null
   
  for (int i = 0; i < SubForms.length(); i = i + 1)
  {
    IDForm currentIdForm = (IDForm)SubForms.getObject(i)
    if (currentIdForm)
    {
      if (CustomDataSubform.isMyInstance(currentIdForm))
         customDataSubform = currentIdForm
    }
  }
   
  if (customDataSubform == null)
  {
    UIBusinessLogic.DTTLogMessage("custom data subform not found in subforms array", ..., DTTWarning)
  }
   
  return customDataSubform
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm MainModuleFormHelper.getWorkflowSubform()
//{
//  IDForm workflowDiagramSubform = null
//   
//  for (int i = 0; i < SubForms.length(); i = i + 1)
//  {
//    IDForm currentIdForm = (IDForm)SubForms.getObject(i)
//    if (currentIdForm)
//    {
//      if (WorkflowDiagramSubform.isMyInstance(currentIdForm))
//         workflowDiagramSubform = currentIdForm
//    }
//  }
//   
//  if (workflowDiagramSubform == null)
//  {
//    UIBusinessLogic.DTTLogMessage("workflow diagram subform not found in subforms array", ..., DTTWarning)
//  }
//   
//  return workflowDiagramSubform
//}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm MainModuleFormHelper.createWorkflowDiagramSubform()
{
  IDForm idf = MainModuleUILogic.createSpecificSubform(WorkflowDiagramSubform)
  return idf
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MainModuleFormHelper.updateCaptionInMainForm(
  string additionalDescription // 
)
{
  string completeCaption = ""
  string mainModuleDescription = Mainmodule.getDescription()
  string moduleCaption = Mainmodule.getCaption(additionalDescription)
   
  completeCaption = moduleCaption + mainModuleDescription
  if (Mainmodule.isClosed())
  {
//    // temporary commented because i want to add the status in another place of the panel
//    string mainModuleIsClosedAdditionalDescr = " - <span class="chiuso">CHIUSO</span>"
    completeCaption = completeCaption
  }
  if (Mainmodule.isLocked())
  {
    UIBusinessLogic.messageBox("Attenzione, stai visualizzando un'anagrafica chiusa, per apportare le modifiche è necessario riaprirla.")
  }
   
  MainForm.caption = completeCaption
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MainModuleFormHelper.handleSave()
{
  boolean valid = Mainmodule.validate(...)
  if (valid)
  {
    Mainmodule.saveToDB(...)
    this.updateCaptionInMainForm("")
     
    // toast notification on SAVE
    string tooltipHTMLTitle = "<div class='saveTooltip'>Salvato <i class='fa fa-save'></i></div>"
    UIBusinessLogic.showTooltip(tooltipHTMLTitle, ..., 0, 3000)
     
    // if there is module specific extra saving code to be executed it is done here, initially this was required to communicate with the diagram of modello evento, but with the new implementation this is not
    // needed anymore. It is something that can be used in the future for other modules
    MainModuleUILogic.performSpecificSavingOperations()
  }
  else 
  {
    this.handleErrorDisplay()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm MainModuleFormHelper.CreateModelloDisposizioniSubform()
{
  IDForm idf = MainModuleUILogic.createSpecificSubform(ModelliDisposizioniSubform)
  return idf
}


// ──────────────────────────────────

// *****************************************************************************************************************
// this centralized onDynamicPropertiesCode is needed to hide the sttange fluid empty rows when the panel is in list
// *****************************************************************************************************************
public static void GlobalPanelEventsHandler.OnDynamicPropertiesRowHiding(
  IDPanel idPanel                            // 
  optional inout int involvedFieldsCount = 0 //  used only for tests
)
{
  UIBusinessLogic.DTTLogMessage(formatMessage("OnDynamicPropertiesRowhiding firing for panel: |1 - layout: |2", idPanel.caption, decode(idPanel.layout, LayoutValues [Panel Library]), ...), ..., DTTInfo)
   
  if (idPanel == null)
    return 
   
  if (idPanel.layout == List)
  {
    boolean rowShouldBeVisible = !(idPanel.isNewRow())
     
    // loop on panel fields to hide them one by one
    int fieldCount = idPanel.fieldsCount()
     
    for (int i = 0; i < fieldCount; i = i + 1)
    {
       
      // we want to hide only fields in list, checking for IsInList we exclude out of list fields (such a button out of list)
      boolean fieldIsInlist = idPanel.getFieldInListList(i)
      if (fieldIsInlist)
      {
         idPanel.setFieldVisible(i, rowShouldBeVisible)
         involvedFieldsCount = involvedFieldsCount + 1
      }
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static TabViewMainPageBuilder TabViewMainPageBuilder.create(
  IDPanel panel                   // 
  optional int buttonsPerRow = 4  // 
  optional int buttonsSizeX = 300 // 
  optional int buttonsSizeY = 100 // 
)
{
  TabViewMainPageBuilder tabViewMPBuilder = new()
  tabViewMPBuilder.setPanel(panel)
  tabViewMPBuilder.setButtonsPerRow(buttonsPerRow)
  tabViewMPBuilder.setButtonsSize(buttonsSizeX, buttonsSizeY)
  return tabViewMPBuilder
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TabViewMainPageBuilder.setPanel(
  IDPanel panel // 
)
{
  MainPagePanel = panel
   
  CommonMainOpzioni d = new()
  MainPagePanel.setDocument(d, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TabViewMainPageBuilder.setButtonsPerRow(
  int elementsPerRow // 
)
{
  ElementsPerRow = elementsPerRow
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TabViewMainPageBuilder.setButtonsSize(
  int width  // 
  int height // 
)
{
  ButtonsWidth = width
  ButtonsHeight = height
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TabViewMainPageBuilder.addButton(
  string caption                                // 
  string code                                   // 
  optional string cssClass = "applicationPanel" // 
)
{
  string caption = caption
  int flags = Visible | InForm | Enabled | NoHeaderInForm
  int i = MainPagePanel.addField("HEADER1", code, Character, 10, ..., flags)
  MainPagePanel.setFieldText(i, caption)
   
  MainPagePanel.setFieldVisualStyle(i, CommandButton)
  MainPagePanel.setFieldActive(i)
  MainPagePanel.setFieldEnabled(i, true)
   
  if (cssClass != "")
  {
    MainPagePanel.setFieldClassName(i, cssClass)
  }
   
  if (CurrentColumn == ElementsPerRow or (CurrentRow == 0 and CurrentColumn == 0))
  {
    FieldPositionHorizontal = 10
    FieldPositionVertical = 10 * ButtonsAlreadyRendered
    CurrentColumn = 1
    CurrentRow = CurrentRow + 1
  }
  else 
  {
    int separator = 10
    FieldPositionHorizontal = FieldPositionHorizontal + separator + ButtonsWidth
    CurrentColumn = CurrentColumn + 1
  }
   
  MainPagePanel.setFieldRect(i, Form, FieldPositionHorizontal, FieldPositionVertical, ButtonsWidth, ButtonsHeight, Move, Move)
  MainPagePanel.calcLayout()
  ButtonsAlreadyRendered = ButtonsAlreadyRendered + 1
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string MainPageFormConfiguration.getCaption()
{
  return "form_caption"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MainPageFormConfiguration.computeTabViewMainPageBuilder(
  IDPanel mainPagePanel // 
)
{
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MainPageFormConfiguration.setupButtons()
{
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm MainPageFormConfiguration.getSubformInstance(
  string code // 
)
{
  return null
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static void MainPageFormInstanceFactory.AssegnaRuoli(
  int:kordapp opzioniKordapp // 
)
{
  MainPageFormConfiguration mainFormConfiguration = new()
  switch (opzioniKordapp)
  {
    case TabelleClientiFornitori:
      CliforConfiguration cc = new()
      mainFormConfiguration = cc
    break
    case TabellePersonale:
      PersonaleConfiguration pc = new()
      mainFormConfiguration = pc
    break
    case ApplicationsManager:
      ApplicationsManagerConfiguration amc = new()
      mainFormConfiguration = amc
    break
    case TabelleDocumenti:
      DocumentiConfiguration dc = new()
      mainFormConfiguration = dc
    break
    case TabelleFunzioni:
      FunzioniConfiguration fc = new()
      mainFormConfiguration = fc
    break
    case TabelleEventi:
      EventiConfiguration ec = new()
      mainFormConfiguration = ec
    break
    default:
      UIBusinessLogic.messageBox("Case not handled")
      return 
    break
  }
   
  if (QappCore.Loggeduser.hasSpecificPrivilege(opzioniKordapp, Execute))
  {
    OpzioniMainPageForm mpf = OpzioniMainPageForm.newInstance(MDI, ...)
    mpf.ShowForm(mainFormConfiguration)
    mpf.bringToFront()
  }
  else 
  {
    UIBusinessLogic.messageBox("Non si possiedono i privilegi necessari per aprire le opzioni.")
    return 
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string CliforConfiguration.getCaption()
{
  return "{{icon-fa-cog}} Opzioni Clienti Fornitori"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CliforConfiguration.computeTabViewMainPageBuilder(
  IDPanel mainPagePanel // 
)
{
  TabViewMainPageBuilder = TabViewMainPageBuilder.create(mainPagePanel, 4, 300, 100)
  return 
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CliforConfiguration.setupButtons()
{
  TabViewMainPageBuilder.addButton(decode({{icon-fa-industryFa-solid}}TipiAnagrafica, OptionsFields), {{icon-fa-industryFa-solid}}TipiAnagrafica, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-barsFa-solid}}Tag, OptionsFields), {{icon-fa-barsFa-solid}}Tag, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-location-dotFa-solid}}Indirizzi, OptionsFields), {{icon-fa-location-dotFa-solid}}Indirizzi, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-linkFa-solid}}Riferimenti, OptionsFields), {{icon-fa-linkFa-solid}}Riferimenti, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati, OptionsFields), {{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm CliforConfiguration.getSubformInstance(
  string code // 
)
{
  IDForm requestedSubform = null
  switch (code)
  {
    case {{icon-fa-industryFa-solid}}TipiAnagrafica:
      requestedSubform = CliforTypes.newInstance(SubForm, ...)
    break
    case {{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati:
      CdataConfiguration ct = CdataConfiguration.newInstance(SubForm, ...)
      ct.setup(ClientiFornitori)
      requestedSubform = ct
    break
    case {{icon-fa-linkFa-solid}}Riferimenti:
      ReferenceTypes ct = ReferenceTypes.newInstance(SubForm, ...)
      ct.setup(ClientiFornitori)
      requestedSubform = ct
    break
    case {{icon-fa-barsFa-solid}}Tag:
      TagClifor ctz = TagClifor.newInstance(SubForm, ...)
      requestedSubform = ctz
    break
    case {{icon-fa-location-dotFa-solid}}Indirizzi:
      Addresses addr = Addresses.newInstance(SubForm, ...)
      requestedSubform = addr
    break
  }
  return requestedSubform
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string PersonaleConfiguration.getCaption()
{
  return "{{icon-fa-cog}} Opzioni Personale"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PersonaleConfiguration.computeTabViewMainPageBuilder(
  IDPanel mainPagePanel // 
)
{
  TabViewMainPageBuilder = TabViewMainPageBuilder.create(mainPagePanel, 4, 300, 100)
  return 
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PersonaleConfiguration.setupButtons()
{
  TabViewMainPageBuilder.addButton(decode({{icon-fa-people-groupFa-solid}}TipiAnagrafica, OptionsFields), {{icon-fa-people-groupFa-solid}}TipiAnagrafica, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-people-arrowsFa-solid}}TipiRapporto, OptionsFields), {{icon-fa-people-arrowsFa-solid}}TipiRapporto, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-tagsFa-solid}}Tag, OptionsFields), {{icon-fa-tagsFa-solid}}Tag, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-file-contractFa-solid}}Contratti, OptionsFields), {{icon-fa-file-contractFa-solid}}Contratti, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-hand-sparklesFa-solid}}Ruoli, OptionsFields), {{icon-fa-hand-sparklesFa-solid}}Ruoli, ...)
   
  TabViewMainPageBuilder.addButton(decode({{icon-fa-linkFa-solid}}Riferimenti, OptionsFields), {{icon-fa-linkFa-solid}}Riferimenti, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati, OptionsFields), {{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati, ...)
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string ApplicationsManagerConfiguration.getCaption()
{
  return "{{icon-fa-key}} Applications Manager"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ApplicationsManagerConfiguration.computeTabViewMainPageBuilder(
  IDPanel mainPagePanel // 
)
{
  TabViewMainPageBuilder = TabViewMainPageBuilder.create(mainPagePanel, 4, 300, 100)
  return 
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ApplicationsManagerConfiguration.setupButtons()
{
  TabViewMainPageBuilder.addButton(decode(Applicazioni, OptionsFields), Applicazioni, ...)
  TabViewMainPageBuilder.addButton(decode(Reparti, OptionsFields), Reparti, ...)
  TabViewMainPageBuilder.addButton(decode(Utenti, OptionsFields), Utenti, ...)
  TabViewMainPageBuilder.addButton(decode(Privilegi, OptionsFields), Privilegi, ...)
  TabViewMainPageBuilder.addButton(decode(Duplications, OptionsFields), Duplications, ...)
  TabViewMainPageBuilder.addButton(decode(LogAccessi, OptionsFields), LogAccessi, ...)
  TabViewMainPageBuilder.addButton(decode(CalendarAltriUtenti, OptionsFields), CalendarAltriUtenti, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm ApplicationsManagerConfiguration.getSubformInstance(
  string code // 
)
{
  IDForm requestedSubform = null
  switch (code)
  {
    case Applicazioni:
      requestedSubform = ApplicazioniSubform.newInstance(SubForm, ...)
    break
    case Reparti:
      requestedSubform = Reparti.newInstance(SubForm, ...)
    break
    case Utenti:
      requestedSubform = Utenti.newInstance(SubForm, ...)
    break
    case Privilegi:
      requestedSubform = Privilegi.newInstance(SubForm, ...)
    break
    case Duplications:
      UITools.displayNotImplementedMessage()
    break
    case LogAccessi:
      UITools.displayNotImplementedMessage()
    break
    case CalendarAltriUtenti:
      requestedSubform = CalendarAltriUtenti.newInstance(SubForm, ...)
    break
  }
  return requestedSubform
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string DocumentiConfiguration.getCaption()
{
  return "{{icon-fa-cog}} Opzioni Documento"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocumentiConfiguration.computeTabViewMainPageBuilder(
  IDPanel mainPagePanel // 
)
{
  TabViewMainPageBuilder = TabViewMainPageBuilder.create(mainPagePanel, 4, 300, 100)
  return 
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm DocumentiConfiguration.getSubformInstance(
  string code // 
)
{
  IDForm requestedSubform = null
  switch (code)
  {
    case {{icon-fa-file-text-o}}TipiFileGestiti:
      requestedSubform = DocTipiFile.newInstance(SubForm, ...)
    break
    case {{icon-fa-location-dotFa-solid}}Ubicazioni:
      requestedSubform = DocUbicazioniForm.newInstance(SubForm, ...)
    break
    case {{icon-fa-file-linesFa-regular}}TipiSupporto:
      requestedSubform = DOCTIPISUPPORTOForm.newInstance(SubForm, ...)
    break
    case {{icon-fa-tagsFa-solid}}TipiTag:
      requestedSubform = DOCTIPITAGForm.newInstance(SubForm, ...)
    break
    case {{icon-fa-fileFa-regular}}TipiDocumento:
      requestedSubform = DOCTipiDocumentoForm.newInstance(SubForm, ...)
    break
    case {{icon-fa-paper-planeFa-solid}}ListeDiDistribuzione:
      requestedSubform = DOCListeDistribuzioneForm.newInstance(SubForm, ...)
       
    break
    case {{icon-fa-gearsFa-solid}}Parametri:
      requestedSubform = DOCParametriForm.newInstance(SubForm, ...)
    break
  }
  return requestedSubform
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string FunzioniConfiguration.getCaption()
{
  return "{{icon-fa-cog}} Opzioni Funzioni"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FunzioniConfiguration.computeTabViewMainPageBuilder(
  IDPanel mainPagePanel // 
)
{
  TabViewMainPageBuilder = TabViewMainPageBuilder.create(mainPagePanel, 4, 300, 100)
  return 
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FunzioniConfiguration.setupButtons()
{
  TabViewMainPageBuilder.addButton(decode({{icon-fa-linkFa-solid}}Riferimenti, OptionsFields), {{icon-fa-linkFa-solid}}Riferimenti, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati, OptionsFields), {{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm FunzioniConfiguration.getSubformInstance(
  string code // 
)
{
  IDForm requestedSubform = null
  switch (code)
  {
    case {{icon-fa-linkFa-solid}}Riferimenti:
      ReferenceTypes rt = ReferenceTypes.newInstance(SubForm, ...)
      rt.setup(Funzioni)
      requestedSubform = rt
    break
    case {{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati:
      CdataConfiguration datiPers = CdataConfiguration.newInstance(SubForm, ...)
      datiPers.setup(Funzioni)
      requestedSubform = datiPers
    break
  }
   
  return requestedSubform
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string EventiConfiguration.getCaption()
{
  return "{{icon-fa-cog}} Opzioni Eventi"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventiConfiguration.computeTabViewMainPageBuilder(
  IDPanel mainPagePanel // 
)
{
  TabViewMainPageBuilder = TabViewMainPageBuilder.create(mainPagePanel, 4, 300, 100)
  return 
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventiConfiguration.setupButtons()
{
  TabViewMainPageBuilder.addButton(decode({{icon-fa-layer-groupFa-solid}}Classi, OptionsFields), {{icon-fa-layer-groupFa-solid}}Classi, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-cubesFa-solid}}Ambiti, OptionsFields), {{icon-fa-cubesFa-solid}}Ambiti, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-share-nodesFa-solid}}Ambiti/Classe, OptionsFields), {{icon-fa-share-nodesFa-solid}}Ambiti/Classe, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-listFa-solid}}Tipologie, OptionsFields), {{icon-fa-listFa-solid}}Tipologie, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-square-checkFa-solid}}Esiti, OptionsFields), {{icon-fa-square-checkFa-solid}}Esiti, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-clipboard-checkFa-solid}}EsitiChecklist, OptionsFields), {{icon-fa-clipboard-checkFa-solid}}EsitiChecklist, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-clipboard-listFa-solid}}EsitiChecklist/Classe, OptionsFields), {{icon-fa-clipboard-listFa-solid}}EsitiChecklist/Classe, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-magnifying-glass-chartFa-solid}}TipiRigaAnalisi, OptionsFields), {{icon-fa-magnifying-glass-chartFa-solid}}TipiRigaAnalisi, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-list-olFa-solid}}TipiDisposizioni, OptionsFields), {{icon-fa-list-olFa-solid}}TipiDisposizioni, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-coinsFa-solid}}TipiCosto, OptionsFields), {{icon-fa-coinsFa-solid}}TipiCosto, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-circle-checkFa-solid}}StatiPubblici, OptionsFields), {{icon-fa-circle-checkFa-solid}}StatiPubblici, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-building-circle-checkFa-solid}}StatiPubblici/Classe, OptionsFields), {{icon-fa-building-circle-checkFa-solid}}StatiPubblici/Classe, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati, OptionsFields), {{icon-fa-bars-staggeredFa-solid}}DatiPersonalizzati, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-linkFa-solid}}Riferimenti, OptionsFields), {{icon-fa-linkFa-solid}}Riferimenti, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-gearFa-solid}}Parametri, OptionsFields), {{icon-fa-gearFa-solid}}Parametri, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-arrow-down-1-9Fa-solid}}Contatori, OptionsFields), {{icon-fa-arrow-down-1-9Fa-solid}}Contatori, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-users-gearFa-solid}}RuoliClassi, OptionsFields), {{icon-fa-users-gearFa-solid}}RuoliClassi, ...)
  TabViewMainPageBuilder.addButton(decode({{icon-fa-users-viewfinderFa-solid}}RuoliAmbiti, OptionsFields), {{icon-fa-users-viewfinderFa-solid}}RuoliAmbiti, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm EventiConfiguration.getSubformInstance(
  string code // 
)
{
  IDForm requestedSubform = null
  switch (code)
  {
    case {{icon-fa-layer-groupFa-solid}}Classi:
       
    break
    case {{icon-fa-cubesFa-solid}}Ambiti:
       
    break
    case {{icon-fa-share-nodesFa-solid}}Ambiti/Classe:
       
    break
    case {{icon-fa-listFa-solid}}Tipologie:
       
    break
    case {{icon-fa-square-checkFa-solid}}Esiti:
      OpzioniEsiti oe = OpzioniEsiti.newInstance(SubForm, ...)
      requestedSubform = oe
    break
    case {{icon-fa-list-checkFa-solid}}Esiti/Classe:
       
    break
    case {{icon-fa-clipboard-checkFa-solid}}EsitiChecklist:
       
    break
    case {{icon-fa-clipboard-listFa-solid}}EsitiChecklist/Classe:
       
    break
    case {{icon-fa-magnifying-glass-chartFa-solid}}TipiRigaAnalisi:
       
    break
    case {{icon-fa-list-olFa-solid}}TipiDisposizioni:
       
    break
    case {{icon-fa-coinsFa-solid}}TipiCosto:
       
    break
    case {{icon-fa-circle-checkFa-solid}}StatiPubblici:
       
    break
    case {{icon-fa-building-circle-checkFa-solid}}StatiPubblici/Classe:
       
    break
  }
   
  if (requestedSubform == null)
  {
    UIBusinessLogic.messageBox("TODO")
  }
   
  return requestedSubform
}


// ──────────────────────────────────



// ──────────────────────────────────

// ***********************************************************************
// helper method for common code on panels, return value depends on cases:
// 1. save: true in case of error found
// 2. cancel: always true (dummy)
// 3. pendingChanges: true if pending changes exist on panel
// ***********************************************************************
public static boolean GlobalPanelOperations.apply(
  IDPanel idPanel                                  // 
  int:centralizedPanelOperationTypes operationType // 
)
{
  boolean result = false
  switch (operationType)
  {
    case save:
      // call here errorReporter method to get all the error in the panel Collection
       
      IDCollection documents of IDDocument = idPanel.collection
      if (documents)
      {
         boolean errorFound = this.AnyDocumentOnPanelHasValidationError(idPanel)
         result = errorFound == false
         if (errorFound)
         {
           ErrorReporter.showErrorsOfDocumentCollection(documents)
         }
         else 
         {
           idPanel.updateData()
         }
      }
    break
    case cancel:
      idPanel.undoChanges()
      result = true
    break
    case pendingChanges:
      IDCollection coll of IDDocument = idPanel.collection
       
      if (coll)
      {
         boolean pendingChangesExist = coll.isModified()
         result = pendingChangesExist
      }
       
    break
  }
   
  return result
}


// ──────────────────────────────────

// ****************************************************
// call this method in the load of a form to.
// make only insert, duplicate, delete commands visible
// make panel non collapsable
// hide the status bar
// optionally clear the caption
// ****************************************************
public static void GlobalPanelOperations.enableOnlyBasicCommands(
  IDPanel idPanel                  // 
  optional boolean showCaption = 0 // if left false caption is cleared, if true the caption is unotouched
)
{
  idPanel.setCommandEnabled(Navigate, false)
  idPanel.setCommandEnabled(FormList, false)
  idPanel.setCommandEnabled(Refresh, false)
  idPanel.setCommandEnabled(Update, false)
  idPanel.showStatusBar(false)
  idPanel.collapsable = false
  if (!(showCaption))
    idPanel.caption = ""
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static boolean GlobalPanelOperations.AnyDocumentOnPanelHasValidationError(
  IDPanel panel // 
)
{
  boolean anyOneDocumentOnPanelIsErrornous = false
  IDCollection documentsOnPanel of IDDocument = panel.collection
  for each IDDocument doc in documentsOnPanel
  {
    boolean isValidDocument = doc.validate(...)
    if (!(isValidDocument))
    {
      anyOneDocumentOnPanelIsErrornous = true
      break 
    }
  }
  return anyOneDocumentOnPanelIsErrornous
}


// ──────────────────────────────────

// ***********************************************************************************************************************
// **************************************************************************************************************
// Creates a tab definition.
// 
// <param name="subformType">Subform type</param>
// <param name="displayOrder">Display order (0, 10, 20...)</param>
// <param name="loadInitially">True to eager load, false for lazy load</param>
// <param name="isFocused">True if this is the focused tab</param>
// <OPTIONAL param name="overrideCaption">Tab caption override: if not passed the design time caption will be used</param>
// <OPTIONAL param name="checkType">Conditional check type (default: None for standard tabs)</param>
// <returns>TabDefinition instance</returns>
// **************************************************************************************************************
// ***********************************************************************************************************************
public static TabDefinition TabDefinition.create(
  string:moduleSubformTypes subformType // 
  int displayOrder                      // 
  boolean loadInitially                 // 
  boolean isFocused                     // 
  optional string overrideCaption = ""  // 
  optional string:conditionalCheckTypes checkType = "none" // 
)
{
  TabDefinition td = new()
  td.SubformType = subformType
  td.Caption = overrideCaption
  td.DisplayOrder = displayOrder
  td.LoadInitially = loadInitially
  td.IsFocused = isFocused
  td.ConditionalCheckType = checkType
  return td
}


// ──────────────────────────────────

public static ModuleTabConfiguration ModuleTabConfiguration.create()
{
  ModuleTabConfiguration td = new()
  td.init()
  return td
}


// ──────────────────────────────────

// *****************************************************
// Adds a static tab to the configuration.
// Static tabs are defined in XTabConfiguration classes.
// 
// <param name="tab">Tab definition to add</param>
// *****************************************************
public void ModuleTabConfiguration.addTab(
  TabDefinition tab // 
)
{
  StaticTabs.addObject(tab)
}


// ──────────────────────────────────

// **************************************************************
// Adds a runtime tab to the configuration.
// Runtime tabs are added dynamically (e.g., by Qapp extensions).
// 
// <param name="tab">Tab definition to add</param>
// **************************************************************
public void ModuleTabConfiguration.addTabAtRuntime(
  TabDefinition tab // 
)
{
  RuntimeTabs.addObject(tab)
}


// ──────────────────────────────────

// *******************************************************************************
// Get all tabs (static + runtime) sorted by displayOrder
//    
// Returns all tabs (static + runtime) sorted by displayOrder.
// This is the main method used by createSubforms().
// 
// <returns>Array of TabDefinition sorted by displayOrder (0, 10, 20...)</returns>
// *******************************************************************************
public IDArray ModuleTabConfiguration.getOrderedTabs()
{
  IDArray allTabs = new()
   
   
  // STEP #1: combine static + runtime tabs
  // add static tabs
  for (int i = 0; i < StaticTabs.length(); i = i + 1)
  {
    allTabs.addObject(StaticTabs.getObject(i))
  }
   
  // add runtime tabs
  for (int j = 0; j < RuntimeTabs.length(); j = j + 1)
  {
    allTabs.addObject(RuntimeTabs.getObject(j))
  }
   
  // STEP #2: Sort by displayOrders
  // Simple algorithm: iterate 0 to 199
  // , collect tabs with that displayOrder
  IDArray orderedTabs = new()
  for (int order = 0; order < 200; order = order + 1)
  {
    for (int k = 0; k < allTabs.length(); k = k + 1)
    {
      TabDefinition tab = (TabDefinition)allTabs.getObject(k)
      if (tab.DisplayOrder == order)
      {
         orderedTabs.addObject(tab)
      }
    }
  }
   
  return orderedTabs
}


// ──────────────────────────────────

// *******************************************************************
// Returns the tab that should be focused (isFocused = true).
// There should be exactly one focused tab per module.
// 
// <returns>The focused TabDefinition, or null if none found</returns>
// *******************************************************************
public TabDefinition ModuleTabConfiguration.getFocusedTab()
{
  TabDefinition focusedTab = null
   
  // Search in static tabs first
  for (int i = 0; i < StaticTabs.length(); i = i + 1)
  {
    TabDefinition tab = (TabDefinition)StaticTabs.getObject(i)
    if (tab.IsFocused)
    {
      focusedTab = tab
      break 
    }
  }
   
  // continue searching only if a focusedTab not found above
  if (focusedTab == null)
  {
    // Search in runtime tabs (unlikely but possible)
    for (int j = 0; j < RuntimeTabs.length(); j = j + 1)
    {
      TabDefinition tab = (TabDefinition)RuntimeTabs.getObject(j)
      if (tab.IsFocused)
      {
         focusedTab = tab
         break 
      }
    }
  }
   
   
  return focusedTab
}


// ──────────────────────────────────

// *****************************************************************
// Returns tabs that should be loaded immediately, in display order.
// This includes:
// - The focused tab (always loaded)
// - Any tab with loadInitially = true
// 
// <returns>Array of TabDefinition to load initially</returns>
// *****************************************************************
public IDArray ModuleTabConfiguration.getTabsToLoadInitially()
{
   
  // get all the tabs in order
  IDArray orderedTabs = this.getOrderedTabs()
   
  // filter those that should be loaded initially
  IDArray toLoad = new()
   
  // STEP #1: combine static + runtime tabs
  // add static tabs
  for (int i = 0; i < orderedTabs.length(); i = i + 1)
  {
    TabDefinition tab = (TabDefinition)orderedTabs.getObject(i)
    if (tab.LoadInitially or tab.IsFocused)
    {
      toLoad.addObject(tab)
    }
  }
   
  return toLoad
}


// ──────────────────────────────────

// *********************************************
// Raised when the document is being initialized
// *********************************************
event ModuleTabConfiguration.OnInit()
{
  StaticTabs = new()
  RuntimeTabs = new()
}


// ──────────────────────────────────

// **********************************************************************************
// Creates a subform instance based on the className.
// Returns null if className is not recognized.
// 
// <param name="subformType">Subform class name (e.g., "CliforDetailSubform")</param>
// <param name="parent">Parent form</param>
// <param name="mainModule">MainModule instance</param>
// 
// <returns>IDForm instance, or null if subformType not found</returns>
// **********************************************************************************
public static IDForm SubformFactory.createSubform(
  TabDefinition tabDefinition // 
)
{
  string:moduleSubformTypes subformType = tabDefinition.SubformType
   
  IDForm subform = null
   
  switch (subformType)
  {
    case CliforDetailSubform:
      CliforDetailSubform cliforDetail = CliforDetailSubform.newInstance(SubForm, ...)
      subform = cliforDetail
    break
    case ContactsOrgchartSubform:
      ContactsOrgchartSubform contacts = ContactsOrgchartSubform.newInstance(SubForm, ...)
      subform = contacts
    break
    case AddressesSubform:
      AddressesSubform addresses = AddressesSubform.newInstance(SubForm, ...)
      subform = addresses
    break
    case PersonaleDetailSubform:
      PersonaleDetailSubform personaleDetail = PersonaleDetailSubform.newInstance(SubForm, ...)
      subform = personaleDetail
    break
    case PersonaleNoteSubform:
      NotePersonaleSubform personaleNote = NotePersonaleSubform.newInstance(SubForm, ...)
      subform = personaleNote
    break
    case CarrieraSubform:
      CarrieraSubform carriera = CarrieraSubform.newInstance(SubForm, ...)
      subform = carriera
    break
    case AmbitiSubform:
      AmbitiSubform ambiti = AmbitiSubform.newInstance(SubForm, ...)
      subform = ambiti
    break
    case EventiDetailSubform:
      EventiDetailSubform eventoDetail = EventiDetailSubform.newInstance(SubForm, ...)
      subform = eventoDetail
    break
    case DisposizioniSubform:
      DisposizioniSubform disposizioni = DisposizioniSubform.newInstance(SubForm, ...)
      subform = disposizioni
    break
    case ModelliAndEventiCostiSubform:
      ModelliAndEventiCostiSubform modelliCosti = ModelliAndEventiCostiSubform.newInstance(SubForm, ...)
      subform = modelliCosti
    break
    case InstructionsSubform:
      InstructionsSubform instructions = InstructionsSubform.newInstance(SubForm, ...)
      subform = instructions
    break
    case WorkflowDiagramSubform:
      WorkflowDiagramSubform diagram = WorkflowDiagramSubform.newInstance(SubForm, ...)
      subform = diagram
    break
    case ModelloEventoDefinizioneSubform:
      ModelloEventoDefinizioneSubform modelloDefinizione = ModelloEventoDefinizioneSubform.newInstance(SubForm, ...)
      subform = modelloDefinizione
    break
    case ModelliDisposizioniSubform:
      ModelliDisposizioniSubform modelloDisposizioni = ModelliDisposizioniSubform.newInstance(SubForm, ...)
      subform = modelloDisposizioni
    break
    case OpzioniModelliSubform:
      OpzioniModelliSubform modelliOpzioni = OpzioniModelliSubform.newInstance(SubForm, ...)
      subform = modelliOpzioni
    break
    case FunzioneDefinizioneSubform:
      FunzioneDefinizioneSubform funzioneDefinizione = FunzioneDefinizioneSubform.newInstance(SubForm, ...)
      subform = funzioneDefinizione
    break
    case FunzioneNominativiSubform:
      FunzioneNominativiSubform funzioneNominativi = FunzioneNominativiSubform.newInstance(SubForm, ...)
      subform = funzioneNominativi
    break
    case FunzioneNoteSubform:
      FunzioneNoteSubform funzioneNote = FunzioneNoteSubform.newInstance(SubForm, ...)
      subform = funzioneNote
    break
    case RiferimentiSubform:
      RiferimentiSubform riferimenti = RiferimentiSubform.newInstance(SubForm, ...)
      subform = riferimenti
    break
    case CustomDataSubform:
      CustomDataSubform customData = CustomDataSubform.newInstance(SubForm, ...)
      subform = customData
    break
    case PromemoriaSubform:
      PromemoriaSubform promemoria = PromemoriaSubform.newInstance(SubForm, ...)
      subform = promemoria
    break
    case DocumentiSubform:
      DocumentiSubform docCol = DocumentiSubform.newInstance(SubForm, ...)
      subform = docCol
    break
    case MainCollegamentiSubform:
      MainCollegamentiSubform collegamenti = MainCollegamentiSubform.newInstance(SubForm, ...)
      subform = collegamenti
    break
    default:
      UIBusinessLogic.DTTLogMessage("SubformFactory.createSubform: Unknown className: " + subformType, ...)
      subform = null
    break
  }
   
  // Tag the subform with its SubformType so consumers (e.g. applyTabConfigDelta)
  // can identify it by config type regardless of runtime class aliasing
  // (e.g. DocumentiSubform type ? DocCollegatiSubform runtime class).
  if (subform != null)
  {
    subform.setTag("subformType", subformType)
  }
   
  if (tabDefinition.Caption != "")
  {
    subform.caption = tabDefinition.Caption
  }
   
  return subform
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDArray MainModuleUILogic.getSubformsArray()
{
  return SubformsArray
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm MainModuleUILogic.getSubformToBeFocused()
{
  return SubformToBeFocused
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MainModuleUILogic.createSubforms()
{
  // Array of IDForms
  SubformsArray = new()
  SubformsToBeInitiallyLoadedArray = new()
   
  // Get filtered tab configuration (already ordered and filtered)
  IDArray filteredTabDefinitions = this.getFilteredTabConfiguration()
   
  // Create subforms from tab definitions
  for (int i = 0; i < filteredTabDefinitions.length(); i = i + 1)
  {
    TabDefinition tabDef = cast(filteredTabDefinitions.getObject(i))
     
    // the beforeSubformCreation and afterSubformCreation methods are extended only where a MainModuleUiLogic subclass wants to perform before or after subform creation code
    this.beforeSubformCreation(tabDef.SubformType)
     
    // Create subform instance using factory
    IDForm subform = SubformFactory.createSubform(tabDef)
     
    this.afterSubformCreation(tabDef.SubformType, subform)
     
    // Add to main array
    SubformsArray.addObject(subform)
     
    // Track focused subform
    if (tabDef.IsFocused)
    {
      SubformToBeFocused = subform
    }
     
    // Track subforms to be initially loaded
    if (tabDef.LoadInitially)
    {
      SubformsToBeInitiallyLoadedArray.addObject(subform)
    }
  }
   
  // Validation: ensure we have a focused subform
  if (SubformToBeFocused == null)
  {
    IDForm firstSubform = null
    if (SubformsArray.length() > 0)
    {
      firstSubform = (IDForm)SubformsArray.getObject(0)
    }
     
     
    if (firstSubform != null)
    {
      SubformToBeFocused = firstSubform
      UIBusinessLogic.DTTLogMessage("createSubforms: No focused subform found in configuration so we focus the first element", ..., DTTInfo)
    }
    else 
    {
      UIBusinessLogic.DTTLogMessage("impossible to set a subform to be focused", ..., DTTError)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static MainModuleUILogic MainModuleUILogic.create(
  MainModule mainmodule // 
)
{
  MainModuleUILogic mmul = this.factory(mainmodule)
   
  mmul.init()
  mmul.MainModule = mainmodule
  mmul.createSubforms()
  return mmul
}


// ──────────────────────────────────

// ****************************************************************
// as a factory should do, this method returns the correct subclass
// ****************************************************************
public static MainModuleUILogic MainModuleUILogic.factory(
  MainModule mainModule // 
)
{
  MainModuleUILogic mmul = null
   
  switch (mainModule.getKordApp())
  {
    case ClientiFornitori:
      CliforUILogic cuil = new()
      mmul = cuil
    break
    case Personale:
      PersonaleUILogic puil = new()
      mmul = puil
    break
    case Eventi:
      EventoUILogic euil = new()
      mmul = euil
    break
    case ModelliEventi:
      ModelloEventoUILogic meuil = new()
      mmul = meuil
    break
    case Funzioni:
      FunzioniUILogic fd = new()
      mmul = fd
    break
    default:
      UIBusinessLogic.DTTLogMessage("NOT SUPPORTED", ..., DTTError)
       
    break
  }
  return mmul
}


// ──────────────────────────────────

// *************************************************************************************************************************************
// This method is specific for Evento and Modello Evento 
// It's used to setup the Main Toolbar visibility and custom buttons 
// 
// since the method is in the superclass we also coded supportDiagramSetup to ensure the method is used only in the classes that need it
// *************************************************************************************************************************************
public void MainModuleUILogic.setupWorkFlowToolbar(
  boolean showToolbar           // 
  IDForm workflowDiagramSubform // 
)
{
  boolean currentClassSupportsDiagramSetup = this.supportDiagramSetup()
   
  if (!(currentClassSupportsDiagramSetup))
  {
    UIBusinessLogic.DTTLogMessage(formatMessage("class |1 does not support diagram setup", typeName(), ...), ..., Tools.getAlternativeForDttErrorInUnitTests(...))
    return 
  }
   
  // define the default commands you want in the mainToolbar
  IDMap undoCommand = new()
  undoCommand.setValue("name", "undo")
  IDArray commands = new()
  commands.addObject(undoCommand)
   
  // define the custom commands you want in the mainToolbar
  IDMap lockCommand = new()
  lockCommand.setValue("name", "blocca-sblocca")
  lockCommand.setValue("text", "Blocca")
  lockCommand.setValue("icon", "lock")
  IDArray customCommands = new()
  customCommands.addObject(lockCommand)
   
  // override to hide the toolbar
  showToolbar = false
   
  // add them in the mainToolbar & display or not the mainToolbar
  DiagramMainToolbar mainToolbarConfiguration = DiagramMainToolbar.Create(showToolbar, commands, customCommands)
  DiagramToolbox toolboxConfiguration = DiagramToolbox.create("visible", false, false, 1, 200, 100)
  DiagramConfiguration diagramConfiguration = DiagramConfiguration.create(..., mainToolbarConfiguration, toolboxConfiguration)
   
  workflowDiagramSubform.sendMessage(readonly, null, -1, ...)
  workflowDiagramSubform.sendMessage(configuration, diagramConfiguration, ...)
   
  // tag set to test that execution of method is completed
  this.setTag("workflowToolbarSetupDone", true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean MainModuleUILogic.supportDiagramSetup()
{
  UIBusinessLogic.DTTLogMessage("ABSTRACT", ..., Tools.getAlternativeForDttErrorInUnitTests(...))
  return false
}


// ──────────────────────────────────

// ***************************************************************************************************************
// method to avoid having the need to read a tag, it returns true if the workflow Toolbar setup has been done
// 
// NOTE: this is mainly for unit tests, to avoid getting tags in unit tests that make tests more difficult tor ead
// ***************************************************************************************************************
public boolean MainModuleUILogic.workflowSetupHasBeenDone()
{
  return getTag("workflowToolbarSetupDone")
}


// ──────────────────────────────────

// ****************************************************************************************************************************************************************************************************************
// if there is module specific extra saving code to be executed it is done here, initially this was required to communicate with the diagram of modello evento, but with the new implementation this is not needed
// anymore. It is something that can be used in the future for other modules
// ****************************************************************************************************************************************************************************************************************
public void MainModuleUILogic.performSpecificSavingOperations()
{
  UIBusinessLogic.DTTLogMessage(formatMessage("for the class |1 there are no specific saving operations", MainModule.typeName(), ...), ..., DTTInfo)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm MainModuleUILogic.createSpecificSubform(
  string:moduleSubformTypes subformType // 
)
{
  this.beforeSubformCreation(subformType)
   
  TabDefinition td = new()
  td.SubformType = subformType
  IDForm subform = SubformFactory.createSubform(td)
   
  this.afterSubformCreation(subformType, subform)
   
  SubformsArray.addObject(subform)
   
  subform.sendMessage("LOAD", ...)
   
  return subform
}


// ──────────────────────────────────

// **************************************************************************
// Get tab configuration (static + runtime combined)
// This is the main entry point for tab configuration system.
//  
// <returns>ModuleTabConfiguration with all tabs (static + runtime)</returns>
// **************************************************************************
public ModuleTabConfiguration MainModuleUILogic.getTabConfiguration()
{
   
  // Step 1: Get static configuration from subclass
  ModuleTabConfiguration config = this.getStaticTabConfiguration()
   
  // Step 2: Add runtime tabs (hook for extensions like Qapp)
  this.addRuntimeTabs(config)
   
  return config
}


// ──────────────────────────────────

// **************************************************************
// Checks if Collegamenti exist for this MainModule.
// Used to determine if Collegamenti tab should be shown.
// 
// <returns>True if collegamenti exist, false otherwise</returns>
// **************************************************************
public boolean MainModuleUILogic.checkCollegamentiExist()
{
  boolean collegamentiExist = false
   
  int count = MainModule.loadCollegamenti(true)
  collegamentiExist = count > 0
   
  return collegamentiExist
}


// ──────────────────────────────────

// ***********************************************************************
// Evaluates a conditional check for tab visibility.
// Used for tabs like Collegamenti and Workflow that appear conditionally.
// 
// <param name="checkType">Type of check to perform</param>
// <returns>True if tab should be shown, false otherwise</returns>
// ***********************************************************************
public boolean MainModuleUILogic.evaluateConditional(
  string:conditionalCheckTypes checkType // 
)
{
  boolean result = false
   
  switch (checkType)
  {
    case none:
      // Always show (no conditional)
      result = true
    break
    case collegamentiExist:
      result = this.checkCollegamentiExist()
    break
    case workflowExists:
      result = this.checkWorkflowExists()
    break
    case disposizioniExists:
      result = this.checkDisposizioniExists()
    break
    default:
      result = false
      UIBusinessLogic.DTTLogMessage("MainModuleUILogic.evaluateConditional: Unknown checkType: " + checkType, ..., DTTError)
    break
  }
   
  return result
   
}


// ──────────────────────────────────

// *****************************************************************
// Add runtime tabs to configuration based on Qapp extensions.
// Checks MainModule.getKordApp() to determine which tabs to add.
//  
// <param name="config">Configuration to add runtime tabs to</param>
// *****************************************************************
public void MainModuleUILogic.addRuntimeTabs(
  ModuleTabConfiguration config // 
)
{
   
  // Check Qapp extensions
   
  // Example: if (MainModule.getKordApp() == QgapModule.kordApp) { ... }
   
  // Default: no runtime tabs (Qapp checks will be added here later)
   
}


// ──────────────────────────────────

// *********************************************************************
// Filters the static tab configuration by evaluating conditional tabs.
// This method reads the static tab configuration and removes tabs whose
// conditional checks return false.
// 
// @return IDArray of TabDefinition objects that should be displayed
// *********************************************************************
public IDArray MainModuleUILogic.getFilteredTabConfiguration()
{
   
  ModuleTabConfiguration config = this.getStaticTabConfiguration()
  IDArray staticOrderedTabs = config.getOrderedTabs()
   
  IDArray filteredTabs = new()
   
  for (int i = 0; i < staticOrderedTabs.length(); i = i + 1)
  {
    TabDefinition tabDef = cast(staticOrderedTabs.getObject(i))
    boolean appendCurrentTab = false
     
    // first we check for module type check...
    // Check ModuleType visibility (respects TipoClifor, TipoPersonale, etc. settings)
    ModuleType moduleType = MainModule.getType()
    boolean shouldBeVisibleModuleTypeCheck = false
    if (moduleType != null)
    {
      shouldBeVisibleModuleTypeCheck = moduleType.shouldTabBeVisible(tabDef.SubformType)
    }
     
    boolean conditionalCheck = false
     
    // ...then we go for conditional check
    if (tabDef.ConditionalCheckType == none)
    {
      conditionalCheck = true
    }
    else 
    {
      boolean conditionMet = this.evaluateConditional(tabDef.ConditionalCheckType)
      conditionalCheck = conditionMet
    }
    appendCurrentTab = (shouldBeVisibleModuleTypeCheck and conditionalCheck)
    UIBusinessLogic.DTTLogMessage(formatMessage("|1 adding tab |2 for main id |3", if(appendCurrentTab, "", "NOT"), tabDef.SubformType, MainModule.getMainID(), ...), 4444, ...)
    if (appendCurrentTab)
    {
      filteredTabs.addObject(tabDef)
    }
  }
   
  return filteredTabs
}


// ──────────────────────────────────

// ***************************************************************************
// Get static tab configuration for this module.
// MUST be overridden in each subclass (CliforUILogic, PersonaleUILogic, etc.)
//  
// <returns>ModuleTabConfiguration with static tabs</returns>
// ***************************************************************************
public ModuleTabConfiguration MainModuleUILogic.getStaticTabConfiguration()
{
  UIBusinessLogic.DTTLogMessage("ABSTRACT", ..., DTTError)
   
   
  // to avoid returning null we return an empty config. BUT THE METHOD MUST BE EXTENDED!!!!
  ModuleTabConfiguration mtc = ModuleTabConfiguration.create()
  return mtc
}


// ──────────────────────────────────

// ***********************************************************
// Checks if workflow is enabled for this module.
// Default: false (no workflow).
// Override in EventoUILogic and ModelloEventoUILogic.
// 
// <returns>True if workflow exists, false otherwise</returns>
// ***********************************************************
public boolean MainModuleUILogic.checkWorkflowExists()
{
   
  // Default: no workflow
  // Override in Evento and ModelloEvento subclasses
  return false
}


// ──────────────────────────────────

// ******************************************************************************************************
// Checks if dispsoizioni tab must be shown for this module.
// Default: false (no tab).
// Override in EventoUILogic since in modelli eventi where the tab visibility depents on modello behavior
// 
// <returns>True if disposizioni  exists, false otherwise</returns>
// ******************************************************************************************************
public boolean MainModuleUILogic.checkDisposizioniExists()
{
   
  // Default: no disposizioni
  // Override in Evento and ModelloEvento subclasses
  return false
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MainModuleUILogic.afterSubformCreation(
  string:moduleSubformTypes subformType // 
  IDForm subform                        // 
)
{
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MainModuleUILogic.beforeSubformCreation(
  string:moduleSubformTypes subformType // 
)
{
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public ModuleTabConfiguration CliforUILogic.getStaticTabConfiguration()
{
   
  ModuleTabConfiguration cliforConfig = ModuleTabConfiguration.create()
   
  // 
  cliforConfig.addTab(TabDefinition.create(CliforDetailSubform, 0, true, true, ...))
  cliforConfig.addTab(TabDefinition.create(RiferimentiSubform, 10, false, false, ...))
  cliforConfig.addTab(TabDefinition.create(CustomDataSubform, 20, false, false, ...))
  cliforConfig.addTab(TabDefinition.create(ContactsOrgchartSubform, 30, true, false, ...))
  cliforConfig.addTab(TabDefinition.create(PromemoriaSubform, 40, false, false, ...))
  cliforConfig.addTab(TabDefinition.create(DocumentiSubform, 50, false, false, ...))
  cliforConfig.addTab(TabDefinition.create(AddressesSubform, 60, false, false, ...))
  cliforConfig.addTab(TabDefinition.create(MainCollegamentiSubform, 70, false, false, "", collegamentiExist))
   
  return cliforConfig
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public ModuleTabConfiguration PersonaleUILogic.getStaticTabConfiguration()
{
   
  ModuleTabConfiguration personaleConfig = ModuleTabConfiguration.create()
   
  personaleConfig.addTab(TabDefinition.create(PersonaleDetailSubform, 0, true, true, ...))
  personaleConfig.addTab(TabDefinition.create(RiferimentiSubform, 10, false, false, ...))
  personaleConfig.addTab(TabDefinition.create(CustomDataSubform, 20, false, false, ...))
  personaleConfig.addTab(TabDefinition.create(CarrieraSubform, 30, false, false, ...))
  personaleConfig.addTab(TabDefinition.create(AmbitiSubform, 40, false, false, ...))
  personaleConfig.addTab(TabDefinition.create(PersonaleNoteSubform, 50, false, false, ...))
  personaleConfig.addTab(TabDefinition.create(PromemoriaSubform, 60, false, false, ...))
  personaleConfig.addTab(TabDefinition.create(DocumentiSubform, 70, false, false, ...))
  personaleConfig.addTab(TabDefinition.create(MainCollegamentiSubform, 80, false, false, "", collegamentiExist))
   
  return personaleConfig
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public ModuleTabConfiguration EventoUILogic.getStaticTabConfiguration()
{
   
  ModuleTabConfiguration eventoConfig = ModuleTabConfiguration.create()
   
  // 
  eventoConfig.addTab(TabDefinition.create(EventiDetailSubform, 0, true, true, ...))
  // 
  eventoConfig.addTab(TabDefinition.create(RiferimentiSubform, 10, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(CustomDataSubform, 20, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(DisposizioniSubform, 30, false, false, "", disposizioniExists))
   
  eventoConfig.addTab(TabDefinition.create(WorkflowDiagramSubform, 40, false, false, ..., workflowExists))
  eventoConfig.addTab(TabDefinition.create(ModelliAndEventiCostiSubform, 50, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(PromemoriaSubform, 60, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(DocumentiSubform, 70, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(MainCollegamentiSubform, 80, false, false, "", collegamentiExist))
  eventoConfig.addTab(TabDefinition.create(InstructionsSubform, 90, false, false, ...))
   
  return eventoConfig
}


// ──────────────────────────────────

// ***********************************************************
// Checks if workflow is enabled for this module.
// Default: false (no workflow).
// Override in EventoUILogic and ModelloEventoUILogic.
// 
// <returns>True if workflow exists, false otherwise</returns>
// ***********************************************************
public boolean EventoUILogic.checkWorkflowExists()
{
  Evento currentEvento = cast(MainModule)
   
  boolean workflowExists = currentEvento.WORKFLOWTYPE == Workflow
   
  return workflowExists
}


// ──────────────────────────────────

// ****************************************************************
// Checks if dispsoizioni tab must be shown for this module.
// Default: false (no tab).
// Override in EventoUILogic and ModelloEventoUILogic.
// 
// <returns>True if disposizioni  exists, false otherwise</returns>
// ****************************************************************
public boolean EventoUILogic.checkDisposizioniExists()
{
   
  // in eventi disposizioni exists in static tabs always (it could be hidden only because classe evento setting)
  return true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventoUILogic.afterSubformCreation(
  string:moduleSubformTypes subformType // 
  IDForm subform                        // 
)
{
   
  if (subformType == WorkflowDiagramSubform)
  {
    Evento currentEvento = cast(MainModule)
    if (currentEvento.WORKFLOWTYPE == Workflow)
    {
      WorkflowDiagramSubform workflowDiagramSubform = cast(subform)
      ModelloEvento currentModelloEvento = currentEvento.getModelloEvento()
      Disposizione currentDisposizione = currentEvento.getNonClosedWorkflowDisposizione()
      workflowDiagramSubform.CurrentDisposizione = currentDisposizione
      workflowDiagramSubform.UpdateJsDiagram(currentModelloEvento, currentDisposizione)
      base.setupWorkFlowToolbar(false, workflowDiagramSubform)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean EventoUILogic.supportDiagramSetup()
{
  return true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public ModuleTabConfiguration ModelloEventoUILogic.getStaticTabConfiguration()
{
   
  ModuleTabConfiguration eventoConfig = ModuleTabConfiguration.create()
   
  eventoConfig.addTab(TabDefinition.create(ModelloEventoDefinizioneSubform, 0, true, true, ...))
  eventoConfig.addTab(TabDefinition.create(OpzioniModelliSubform, 10, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(RiferimentiSubform, 20, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(CustomDataSubform, 30, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(ModelliDisposizioniSubform, 40, true, false, "", disposizioniExists))
   
  // modelliCosti is wrong here: btw we have the task to make a centralized costi tab
  // so that time we'll fix also here!
  eventoConfig.addTab(TabDefinition.create(WorkflowDiagramSubform, 50, false, false, "", workflowExists))
  eventoConfig.addTab(TabDefinition.create(ModelliAndEventiCostiSubform, 60, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(DocumentiSubform, 70, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(InstructionsSubform, 80, false, false, ...))
  eventoConfig.addTab(TabDefinition.create(MainCollegamentiSubform, 90, false, false, "", collegamentiExist))
   
  return eventoConfig
}


// ──────────────────────────────────

// ***********************************************************
// Checks if workflow is enabled for this module.
// Default: false (no workflow).
// Override in EventoUILogic and ModelloEventoUILogic.
// 
// <returns>True if workflow exists, false otherwise</returns>
// ***********************************************************
public boolean ModelloEventoUILogic.checkWorkflowExists()
{
  ModelloEvento currentModelloEvento = cast(MainModule)
   
  boolean workflowExists = currentModelloEvento.WORKFLOWTYPE == Workflow
  //  
  // in Modelli Eventi we show it only if behavior is workflow
  // 
  return workflowExists
}


// ──────────────────────────────────

// ****************************************************************
// Checks if dispsoizioni tab must be shown for this module.
// Default: false (no tab).
// Override in EventoUILogic and ModelloEventoUILogic.
// 
// <returns>True if disposizioni  exists, false otherwise</returns>
// ****************************************************************
public boolean ModelloEventoUILogic.checkDisposizioniExists()
{
   
  // in modello evento show tab if ! workflow
  return !(this.checkWorkflowExists())
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelloEventoUILogic.beforeSubformCreation(
  string:moduleSubformTypes subformType // 
)
{
  if (subformType == WorkflowDiagramSubform)
  {
    ModelloEvento currentModelloEvento = cast(MainModule)
    if (currentModelloEvento.WORKFLOWTYPE == Workflow)
    {
      // Load workflow collection. needed by Evento class
      currentModelloEvento.loadWorkflowCollections()
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelloEventoUILogic.afterSubformCreation(
  string:moduleSubformTypes subformType // 
  IDForm subform                        // 
)
{
  if (subformType == WorkflowDiagramSubform)
  {
    ModelloEvento currentModelloEvento = cast(MainModule)
    if (currentModelloEvento.WORKFLOWTYPE == Workflow)
    {
      WorkflowDiagramSubform workflowDiagramSubform = cast(subform)
      workflowDiagramSubform.UpdateJsDiagram(currentModelloEvento, ...)
       
      WorkflowSubform = workflowDiagramSubform
      base.setupWorkFlowToolbar(true, workflowDiagramSubform)
    }
  }
  if (subformType == DocumentiSubform)
  {
    DocumentiSubform ds = cast(subform)
    if (ds)
    {
      ds.caption = "{{icon-fa-paperclip}} Doc Collegati"
      ds.enterModelloEventoMode()
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean ModelloEventoUILogic.supportDiagramSetup()
{
  return true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public ModuleTabConfiguration FunzioniUILogic.getStaticTabConfiguration()
{
   
  ModuleTabConfiguration funzioneConfig = ModuleTabConfiguration.create()
   
  funzioneConfig.addTab(TabDefinition.create(FunzioneDefinizioneSubform, 0, true, true, ...))
  funzioneConfig.addTab(TabDefinition.create(RiferimentiSubform, 10, false, false, ...))
  funzioneConfig.addTab(TabDefinition.create(CustomDataSubform, 20, false, false, ...))
  funzioneConfig.addTab(TabDefinition.create(FunzioneNominativiSubform, 30, false, false, ...))
  funzioneConfig.addTab(TabDefinition.create(PromemoriaSubform, 40, false, false, ...))
  funzioneConfig.addTab(TabDefinition.create(DocumentiSubform, 50, false, false, ...))
  funzioneConfig.addTab(TabDefinition.create(FunzioneNoteSubform, 60, false, false, ...))
  funzioneConfig.addTab(TabDefinition.create(MainCollegamentiSubform, 70, false, false, "", collegamentiExist))
   
  return funzioneConfig
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static IDArray ArrayTools.insertObjectAtPosition(
  IDArray inputArray        // 
  object objectToBeInserted // 
  int position              // zero based
)
{
  if (isNull(position))
    position = 0
   
  if (inputArray == null)
  {
    UIBusinessLogic.DTTLogMessage("Input array cannot be null", ..., Tools.getAlternativeForDttErrorInUnitTests(...))
    return null
  }
   
  if (objectToBeInserted == null)
  {
    UIBusinessLogic.DTTLogMessage("objectToBeInserted cannot be null", ..., Tools.getAlternativeForDttErrorInUnitTests(...))
    return inputArray
  }
   
  IDArray result = new()
   
  // when too big position passed we append at the end
  if (position > inputArray.length())
  {
    position = inputArray.length()
  }
   
  for (int j = 0; j <= inputArray.length(); j = j + 1)
  {
     
    if (j < position)
    {
      result.addObject(inputArray.getObject(j))
    }
    else if (j == position)
    {
      result.addObject(objectToBeInserted)
    }
    else 
    {
      result.addObject(inputArray.getObject(j - 1))
    }
  }
  return result
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static FileUploaderHandler FileUploaderHandler.create()
{
  FileUploaderHandler fuh = new()
  fuh.init()
  return fuh
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FileUploaderHandler.setMode(
  string:documentUploadModes mode // 
)
{
  UploadMode = mode
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FileUploaderHandler.handleOnFileUploadedEvent(
  IDForm Form         // 
  inout string SaveTo // 
)
{
  this.setCallerForm(Form)
  this.addFile(SaveTo)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FileUploaderHandler.notifyCallerForm()
{
  if (CallerForm)
  {
    CallerForm.sendMessage("FILE_UPLOAD_COMPLETED", ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FileUploaderHandler.setCallerForm(
  IDForm callerForm // 
)
{
  CallerForm = callerForm
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FileUploaderHandler.addFile(
  string filePath // 
)
{
  if (UploadMode == singleFile)
  {
    if (FilePathsArray.length() == 0)
    {
      FilePathsArray.addValue(filePath)
    }
  }
  else 
  {
    FilePathsArray.addValue(filePath)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDArray FileUploaderHandler.getFiles(
  optional string:getFilesModes mode = "clearArray" // 
)
{
  IDArray ida = this.getCopyOfFilePathsArray()
  if (mode == clearArray)
    FilePathsArray.clear()
  return ida
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDArray FileUploaderHandler.getCopyOfFilePathsArray()
{
  IDArray copyOfFilePathsArray = new()
  for (int i = 0; i < FilePathsArray.length(); i = i + 1)
  {
    copyOfFilePathsArray.addValue(FilePathsArray.getValue(i))
  }
  return copyOfFilePathsArray
}


// ──────────────────────────────────

// *********************************************
// Raised when the document is being initialized
// *********************************************
event FileUploaderHandler.OnInit()
{
  FilePathsArray = new()
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDCollection SendMessageData.getCollectionOfIdDocument()
{
  return CollectionOfIdDocument
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void SendMessageData.setCollectionOfIdDocument(
  IDCollection collectionOfIdDocument of IDDocument // 
)
{
  CollectionOfIdDocument = collectionOfIdDocument
}


// ──────────────────────────────────

// *********************************************
// Raised when the document is being initialized
// *********************************************
event PanelRowButtonRepository.OnInit()
{
  RepositoriesMap = new()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public PanelRowButtonController PanelRowButtonRepository.getPanelRowButtonController(
  IDPanel idPanel // 
)
{
  string panelGUID = idPanel.GUID()
  PanelRowButtonController prbc = (PanelRowButtonController)RepositoriesMap.getObject(panelGUID)
  return prbc
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PanelRowButtonRepository.addPanelRowButtonController(
  PanelRowButtonController panelRowButtonController // 
)
{
  IDPanel idp = panelRowButtonController.getIdPanel()
  string panelGUID = idp.GUID()
   
  DevTools.ToBeReviewed("For multiple subforms (like riferimenti) this approach DOES NOT WORK")
  RepositoriesMap.setObject(panelGUID, panelRowButtonController)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static void PanelRowButtonRepository.instantiateSingleton()
{
   
  if (UIBusinessLogic.PanelRowButtonRepository != null)
  {
    UIBusinessLogic.DTTLogMessage("it is not possible to instantiate the singleton more times!", ..., DTTError)
  }
   
  UIBusinessLogic.PanelRowButtonRepository = new()
  UIBusinessLogic.PanelRowButtonRepository.init()
}


// ──────────────────────────────────

// ***************************************************************************************
// method to be called in a Global Panel Activate Field event
// 
// it tries to retrieve from the repository a row button controller for the specific panel
// if found it tries to perform the action linked to the button
// ***************************************************************************************
public void PanelRowButtonRepository.globalPanelActivateFieldHandler(
  IDPanel Panel  // 
  int FieldIndex // 
)
{
  PanelRowButtonController prbc = UIBusinessLogic.PanelRowButtonRepository.getPanelRowButtonController(Panel)
  if (prbc)
  {
     
    // store field index for later (in mouse click) use...
    prbc.setFieldIndex(FieldIndex)
    prbc.performActionIfPossible(onPanelActivateField, ...)
  }
}


// ──────────────────────────────────

// ***************************************************************************************
// method to be called in a Global Panel Activate Field event
// 
// it tries to retrieve from the repository a row button controller for the specific panel
// if found it tries to perform the action linked to the button
// ***************************************************************************************
public void PanelRowButtonRepository.globalPanelMouseClickHandler(
  IDPanel Panel // 
  int:mouseButtons Button // 
  int XB        // 
  int YB        // 
  int Column    // 
)
{
  IDCollection coll of IDDocument = Panel.collection
  if (coll)
  {
    if (coll.count() <= 0)
    {
      return 
    }
  }
   
  // if user clicks below the last row we do nothing: strangely Column == -1 is the condition to check (and not Row == -1)
  if (Column == -1)
  {
    return 
  }
   
  PanelRowButtonController prbc = UIBusinessLogic.PanelRowButtonRepository.getPanelRowButtonController(Panel)
  if (prbc == null)
    return 
   
  MouseClickInformation mci = MouseClickInformation.create(XB, YB, Button)
  if (prbc.activateFieldWasCalledBefore())
  {
     
    prbc.performActionIfPossible(onPanelMouseClick, mci)
    prbc.markAsActivateFieldHandled()
  }
  else if (mci.MouseButton == Right)
  {
     
    // special handling of right click
    PopupmenuRowButtonController pmrbc = prbc.getPopupController()
    pmrbc.perform(mci)
     
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDPanel PanelRowButtonController.getIdPanel()
{
  return IdPanel
}


// ──────────────────────────────────

// ************************************************************************
// creates and returns a panel row button controller and adds to repository
// the returned object can then be setup
// 
// this method is meaant to be called on a form load
// ************************************************************************
public static PanelRowButtonController PanelRowButtonController.create(
  IDPanel idPanel // 
  IDForm idForm   // 
)
{
  if (idPanel == null)
  {
    UIBusinessLogic.DTTLogMessage("Null idPanel passed", ..., DTTError)
  }
  if (idForm == null)
  {
    UIBusinessLogic.DTTLogMessage("Null idForm passed", ..., DTTError)
  }
   
  PanelRowButtonController prbc = new()
  prbc.setIdPanel(idPanel)
  prbc.setIdForm(idForm)
  UIBusinessLogic.PanelRowButtonRepository.addPanelRowButtonController(prbc)
  return prbc
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PanelRowButtonController.setIdPanel(
  IDPanel idPanel // 
)
{
  IdPanel = idPanel
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PanelRowButtonController.setIdForm(
  IDForm idForm // 
)
{
  IdForm = idForm
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PanelRowButtonController.addButtonController(
  RuntimeRowButtonController buttonController // 
)
{
   
  // store a reference to the parent
  buttonController.PanelRowButtonController = this
   
  RuntimeRowButtonController.add(buttonController)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void PanelRowButtonController.renderButtons()
{
  for each RuntimeRowButtonController rrbc in RuntimeRowButtonController
  {
    rrbc.renderPanelField()
  }
}


// ──────────────────────────────────

// **********************************************************************************************
// if for the panel and fieldIndex a controller exists, the matching action is performed
// 
// mouseClickInformation makes sense only when performActionIsPossible is called by onclick event
// **********************************************************************************************
public void PanelRowButtonController.performActionIfPossible(
  string:supportedPanelEventTypes eventType            // 
  optional MouseClickInformation mouseClickInformation // 
)
{
  int fieldIndex = this.getFieldIndex()
  RuntimeRowButtonController rrbc = this.getMatchingControllerByFieldIndex(fieldIndex)
   
  if (rrbc != null)
  {
    string:supportedPanelEventTypes supportedEventType = rrbc.getSupportedEventType()
    if (supportedEventType == eventType)
    {
      rrbc.perform(mouseClickInformation)
    }
  }
  else 
    UIBusinessLogic.DTTLogMessage(formatMessage("no button controller found for FieldIndex |1", fieldIndex, ...), ..., DTTInfo)
   
}


// ──────────────────────────────────

// ***************************************************
// finds if possible a button controller by fieldIndex
// ***************************************************
private RuntimeRowButtonController PanelRowButtonController.getMatchingControllerByFieldIndex(
  int fieldIndex // 
)
{
  RuntimeRowButtonController foundController = null
  for each RuntimeRowButtonController rrbc in RuntimeRowButtonController
  {
    if (rrbc.FieldIndex == fieldIndex)
    {
      foundController = rrbc
      break 
    }
  }
   
  if (foundController == null)
  {
    UIBusinessLogic.DTTLogMessage(formatMessage("button controller not found for fieldIndex |1", fieldIndex, ...), ..., DTTInfo)
  }
   
  return foundController
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm PanelRowButtonController.getIdForm()
{
  return IdForm
}


// ──────────────────────────────────

// *************************************************************************************
// finds if possible a button controller that handles popup (it might also not be there)
// *************************************************************************************
public PopupmenuRowButtonController PanelRowButtonController.getPopupController()
{
  RuntimeRowButtonController foundController = null
  for each RuntimeRowButtonController rrbc in RuntimeRowButtonController
  {
    string:supportedPanelEventTypes supportedEventType = rrbc.getSupportedEventType()
    if (supportedEventType == onPanelMouseClick)
    {
      foundController = rrbc
      break 
    }
  }
   
  if (foundController == null)
  {
    UIBusinessLogic.DTTLogMessage(formatMessage("button controller not found for onPanelMouseClick for panel |1", IdPanel.GUID(), ...), ..., DTTInfo)
  }
   
  PopupmenuRowButtonController prbc = cast(foundController)
   
  return prbc
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PanelRowButtonController.setFieldIndex(
  int fieldIndex // 
)
{
  FieldIndex = fieldIndex
  ActivateFieldWasCalledBefore = true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public int PanelRowButtonController.getFieldIndex()
{
  return FieldIndex
}


// ──────────────────────────────────

// *******************************************************************************************************************************************************************************************************
// returns true the controller has already been "sensed" by activate field event (who fires before on mouse click)
// if this is the case the controller knows that the user tried to click on a button (so it will go for "left" click management), while the non activated path is tipically for right mouse click handling
// *******************************************************************************************************************************************************************************************************
public boolean PanelRowButtonController.activateFieldWasCalledBefore()
{
  return ActivateFieldWasCalledBefore
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PanelRowButtonController.markAsActivateFieldHandled()
{
  ActivateFieldWasCalledBefore = false
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static RuntimeRowButtonController RuntimeRowButtonController.factory(
  string:runtimeRowButtonTypes type          // 
  string:rowButtonDisplayModes displayMode   // 
  string:rowButtonBehaviorModes behaviorMode // 
  optional IDCommand popupmenu               // 
)
{
  RuntimeRowButtonController rrbc = null
   
  switch (type)
  {
    case delete:
      DeleteRowButtonController drbc = new()
      drbc.Behaviormode = behaviorMode
      rrbc = drbc
    break
    case popupmenu:
      PopupmenuRowButtonController prbc = PopupmenuRowButtonController.create(popupmenu)
      rrbc = prbc
    break
  }
   
  rrbc.DisplayMode = displayMode
   
  return rrbc
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void RuntimeRowButtonController.renderPanelField()
{
  string buttonDBCode = this.getIcon()
  int defaultFlags = 0 | Visible | InList | ListList | Enabled
  int groupID = -1
   
  IDPanel panel = PanelRowButtonController.getIdPanel()
   
  // change here the visual Style for the row buttons
  int visualStyleForRowButtons = CommandButton
   
  int fieldIndex = panel.addField(" ", buttonDBCode, Character, 0, ..., defaultFlags, 1, visualStyleForRowButtons, groupID)
  panel.setFieldRect(fieldIndex, List, 30, 30, 52, 30, None, None)
  panel.setFieldHeaderSize(fieldIndex, List, 100)
   
  // PROVA
  panel.setFieldOnlyIcon(fieldIndex, true)
  panel.setFieldEnabled(fieldIndex, true)
  panel.setFieldActive(fieldIndex)
   
  string buttonTooltip = this.getTooltip()
  panel.setFieldTooltip(fieldIndex, buttonTooltip)
  panel.setFieldCaption(fieldIndex, " ")
   
   
  // only in case displayMod is left we need to move the field, otherwise it is already added at the end (=at the right)
  if (DisplayMode == left)
  {
    // move will work only if advanced tab order is manually set at design time to the panel!
    // the rendered field is moved before field 0, so at the beginning
    panel.move(fieldIndex, 0, List)
  }
   
  // store the fieldIndex so the field can be identified later
  FieldIndex = fieldIndex
   
  panel.calcLayout()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string RuntimeRowButtonController.getIcon()
{
  UIBusinessLogic.DTTLogMessage("ABSTRACT", ..., DTTError)
  return null
}


// ──────────────────────────────────

// ********************************************************************************************************************
// imlements the specific button operation, it must be extended
// 
// the parameter is used only in some subclasses but being this an abstract method we need to pass it in the superclass
// ********************************************************************************************************************
public void RuntimeRowButtonController.perform(
  MouseClickInformation mouseClickInformation // 
)
{
  UIBusinessLogic.DTTLogMessage("ABSTRACT", ..., DTTError)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string RuntimeRowButtonController.getTooltip()
{
  UIBusinessLogic.DTTLogMessage("ABSTRACT", ..., DTTError)
  return null
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string RuntimeRowButtonController.getSupportedEventType()
{
  UIBusinessLogic.DTTLogMessage("ABSTRACT", ..., DTTError)
  return null
}


// ──────────────────────────────────

// ************************************************************
// imlements the specific button operation, it must be extended
// 
// 
// ************************************************************
public void DeleteRowButtonController.perform(
  MouseClickInformation mouseClickInformation // 
)
{
  IDPanel idp = PanelRowButtonController.getIdPanel()
  IDForm idf = PanelRowButtonController.getIdForm()
   
  boolean isDoPanel = idp.isDO()
   
  IDDocument doc = null
  if (isDoPanel)
  {
    UIBusinessLogic.DTTLogMessage(idp.caption, ...)
    UIBusinessLogic.DTTLogMessage(idp.totalRows(), ...)
    doc = (IDDocument)idp.document
  }
  else 
  {
    UIBusinessLogic.DTTLogMessage("Only DO Panels supported!", ..., DTTError)
  }
   
  if (this.Behaviormode == ask)
  {
    CommonConfirmationFrom cc = CommonConfirmationFrom.newInstance(Modal, ...)
    cc.ShowForm("Conferma Eliminazione", "ELIMINA", "ANNULLA", idf, "DELETE_ROW", "Sei sicuro di voler eliminare questa riga?", doc, Delete, Delete)
  }
  else 
  {
    idf.sendMessage("DELETE_ROW", doc, ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string DeleteRowButtonController.getIcon()
{
  return "{{icon-vela-trash-04}}"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string DeleteRowButtonController.getTooltip()
{
  return ""
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string DeleteRowButtonController.getSupportedEventType()
{
  return onPanelActivateField
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static PopupmenuRowButtonController PopupmenuRowButtonController.create(
  IDCommand popupmenu // 
)
{
  PopupmenuRowButtonController prbc = new()
  prbc.setPopupmenu(popupmenu)
  return prbc
}


// ──────────────────────────────────

// ************************************************************
// imlements the specific button operation, it must be extended
// ************************************************************
public void PopupmenuRowButtonController.perform(
  MouseClickInformation mouseClickInformation // 
)
{
  int x = mouseClickInformation.X
  int y = mouseClickInformation.Y
   
  Popupmenu.openPopupXY(x, y)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PopupmenuRowButtonController.setPopupmenu(
  IDCommand popupMenu // 
)
{
  Popupmenu = popupMenu
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string PopupmenuRowButtonController.getIcon()
{
  return "{{icon-vela-dots-vertical}}"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string PopupmenuRowButtonController.getTooltip()
{
  return ""
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string PopupmenuRowButtonController.getSupportedEventType()
{
  return onPanelMouseClick
}


// ──────────────────────────────────

// ******************************************************************************************************************************************
// replaces "{{icon-vela-something}}" with "{{}}" so the count of chars is correct, since the icon is somehow "4 chars large" we leave "{{}}"
// 
// it supports more icons in the same string
// ******************************************************************************************************************************************
public static string PopupmenuRowButtonController.replaceIconWithChar(
  string inputString // 
)
{
  string startTag = "{{icon-"
  string endTag = "}}"
   
  int searchFrom = 1
  while (true)
  {
    int start = find(inputString, startTag, searchFrom)
    if (start == 0)
      break 
     
    int end = find(inputString, endTag, start)
    if (end == 0)
      break 
     
    int after = end + length(endTag)
    if ((after < length(inputString)) and (mid(inputString, after + 1, 1) == " "))
      after = after + 1
     
    int pre = start
    if ((pre > 1) and mid(inputString, pre - 1, 1) == " ")
      pre = pre - 1
     
    string leftPart = if(pre > 1, left(inputString, pre - 1), "")
    string rightPart = if(after < length(inputString), mid(inputString, after + 1, ...), "")
     
    inputString = leftPart + "{{}}" + rightPart
     
    searchFrom = length(leftPart) + 4 + 1
  }
   
   
   
  return inputString
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static MouseClickInformation MouseClickInformation.create(
  int x                   // 
  int y                   // 
  int:mouseButtons button // 
)
{
  MouseClickInformation mci = new()
  mci.X = x
  mci.Y = y
  mci.MouseButton = button
  return mci
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static void UITools.displayNotImplementedMessage()
{
  UIBusinessLogic.messageBox("Not implemented yet.")
}


// ──────────────────────────────────

// **********
// thi
// **********
public static IDCollection WorkflowLogic.cdataLinksUpdateManager(
  IDCollection coll of CdataWkfResultDisplayUIClass // Write a comment for this parameter or press backspace to delete this comment
  WkfResult result                                  // 
)
{
  result.HasCdata = false
   
   
  for each CdataWkfResultDisplayUIClass cwrduic in coll
  {
    boolean found = false
    CdataWkfResultLink existingLink = null
     
    for each CdataWkfResultLink cwrl in result.CdataWkfResultLinks
    {
      if (cwrl.deleted == true)
      {
         continue 
      }
      if (cwrduic.IDRESULT == cwrl.IDRESULT and cwrduic.IDCDATAFLD == cwrl.IDCDATAFLD)
      {
         found = true
         existingLink = cwrl
         break 
      }
    }
    if (found)
    {
      if (cwrduic.ISREADONLY == false and cwrduic.SHOW == false and cwrduic.MANDATORY == false)
      {
         existingLink.deleted = true
      }
      else 
      {
         existingLink.OBBLIGATORIO = if(cwrduic.MANDATORY, Yes, No)
         existingLink.ISREADONLY = if(cwrduic.ISREADONLY, Yes, No)
      }
    }
    else 
    {
      if (cwrduic.SHOW == true or cwrduic.MANDATORY == true or cwrduic.ISREADONLY == true)
      {
         CdataWkfResultLink wkfResultCdata = CdataWkfResultLink.create(cwrduic)
         result.CdataWkfResultLinks.add(wkfResultCdata)
      }
    }
     
    if (cwrduic.SHOW == true or cwrduic.MANDATORY == true or cwrduic.ISREADONLY == true)
    {
      result.HasCdata = true
    }
  }
  return result.CdataWkfResultLinks
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static void ReferenceTypeMenuController.instantiateSingleton()
{
  if (UIBusinessLogic.ReferenceTypeMenuController != null)
  {
    UIBusinessLogic.DTTLogMessage("Cannot reinstantiate singleton", ..., DTTError)
  }
  ReferenceTypeMenuController rtmc = new()
  rtmc.init()
  UIBusinessLogic.ReferenceTypeMenuController = rtmc
}


// ──────────────────────────────────



// ──────────────────────────────────

// **************************************************************************************************
// returns a unique string to identify the tuple mainModule + callerForm used for generating the menu
// **************************************************************************************************
public string ReferenceTypeMenuController.getUniqueMenuIdentifier()
{
  string unique = formatMessage("|1$|2$|3", toString(MainModule.getMainID()), toString(MainModule.getKordApp()), CallerForm.caption, ...)
  return unique
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ReferenceTypeMenuController.globalCommandSetCmdHandler(
  IDCommand Command // 
)
{
  if (left(Command.code, 7) == "NEW_REF")
  {
     
    int idRefType = toInteger(replace(Command.code, "NEW_REF", ""))
    ReferenceType rt = ReferenceType.get(idRefType)
    CallerForm.sendMessage("NEW_REFERENCE_TYPE_SELECTED", rt, ...)
  }
}


// ──────────────────────────────────

// ***************************************************************************************************
// genreates a run time popupmenu and displays it at the top right of the screen
// 
// it returns an array of ID Commands for testing purposes
// 
// source3drId is needed to pass the idCommand (toolbar or popupmenu) under which render the popupmenu
// 
// ***************************************************************************************************
public IDArray ReferenceTypeMenuController.openPopupMenu(
  MainModule mainModule // 
  IDForm callerForm     // 
  string sourceRd3Id    // 
)
{
  IDArray createdMenuItemsArray = new()
   
  MainModule = mainModule
  CallerForm = callerForm
   
   
   
  boolean menuShouldBeBuilt = this.menuShouldBeBuilt()
   
  if (menuShouldBeBuilt)
  {
    createdMenuItemsArray = this.buildMenu()
  }
   
  // opens the popup near the source
  runtimecommandset.openPopupRD3(sourceRd3Id, ...)
   
  return createdMenuItemsArray
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ExportCartellaForm.showForm(
  Cartella cartella // Write a comment for this parameter or press backspace to delete this comment
)
{
   
  // we reload cartella to have a different object so we do not interfer with the one shown in the tree (in loading subfolders thre are problems)
  Cartella reloadedCartella = Cartella.get(cartella.IDCARTELLA)
  Cartella.setDocument(reloadedCartella, true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ExportCartellaForm.Buttondownload()
{
  Cartella c = Cartella.document
  if (c)
  {
    int trackPhaseCount = 0
    int subfoldersCount = 0
    string outputFolder = c.exportFiles(trackPhaseCount, subfoldersCount, "")
     
    string zipFileName = UIBusinessLogic.tempPath + FH.getSeparator() + c.DESCRCARTELLA + ".zip"
    string zippedFile = IDZip.zip(outputFolder, zipFileName, ...)
    UIBusinessLogic.openDocument(zippedFile, ...)
    this.close(true)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ExportCartellaForm.buttonCancel()
{
  if (this.Exitoncancel)
    Tools.performExit(...)
  else 
  {
    this.close(false)
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event ReferenceTypes.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(TipiRiferimento.IDPanel(), ...)
  GlobalPanelOperations.enableOnlyBasicCommands(DatipersRiferimenti.IDPanel(), ...)
  GlobalPanelOperations.enableOnlyBasicCommands(kordappselectionpanel.IDPanel(), ...)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event ReferenceTypes.TipiRiferimento.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.New()
  }
  if (Command == Duplicate)
  {
    Cancel = true
    ReferenceType rt = TipiRiferimento.document
    if (rt)
    {
      rt.duplicateRefType()
    }
  }
}


// ──────────────────────────────────

// *********************************************************************
// Event raised after saving the data for an edited row to the database.
// *********************************************************************
event ReferenceTypes.kordappselectionpanel.AfterUpdate()
{
  this.filterPanelRecords()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ReferenceTypes.setup(
  int:kordapp kordApp // 
)
{
  MainParameters.SourceKordapp = Articoli
  MainParameters.DestinationKordapp = kordApp
  this.loadReferenceTypes(MainParameters.DestinationKordapp)
  this.filterPanelRecords()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ReferenceTypes.loadReferenceTypes(
  int:kordapp kordApp // Write a comment for this parameter or press backspace to delete this comment
)
{
  IDCollection referenceTypes of ReferenceType = ReferenceType.getReferenceTypes(kordApp)
  TipiRiferimento.setCollection(referenceTypes, true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ReferenceTypes.insert()
{
  IDCollection coll of ReferenceType = TipiRiferimento.collection
  ReferenceType rt = new()
  rt.init()
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ReferenceTypes.SourceRiferimento()
{
  ReferenceType rt = TipiRiferimento.document
  if (rt)
  {
    ModuleTypeSelelction.showForm(rt, Source)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ReferenceTypes.DestinazioneRiferimento()
{
  ReferenceType rt = TipiRiferimento.document
  if (rt)
  {
    ModuleTypeSelelction.showForm(rt, Destination)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ReferenceTypes.New()
{
  IDCollection refTypes of ReferenceType = TipiRiferimento.collection
  ReferenceType rt = ReferenceType.create(MainParameters.DestinationKordapp, MainParameters.SourceKordapp, ...)
  refTypes.add(rt)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ReferenceTypes.filterPanelRecords()
{
  IDCollection panelCollection of ReferenceType = TipiRiferimento.collection
  for each ReferenceType rt in panelCollection
  {
    rt.hidden = rt.SourceKordapp != MainParameters.SourceKordapp
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModuleTypeSelelction.showForm(
  ReferenceType refType                // Write a comment for this parameter or press backspace to delete this comment
  string:referenceModuleTypesMode mode // 
)
{
  refType.loadCollections()
   
  this.Mode = mode
   
  switch (mode)
  {
    case Source:
      this.caption = "Origine riferimento"
      ReferenceModuleType.setCollection(refType.SourceModuleTypes, ...)
    break
    case Destination:
      this.caption = "Destinazione riferimento"
      ReferenceModuleType.setCollection(refType.DestinationModuleTypes, ...)
    break
  }
   
  for each ReferenceModuleType rmt in refType.SourceModuleTypes
  {
    UIBusinessLogic.DTTLogMessage(rmt.IdType, ...)
    UIBusinessLogic.DTTLogMessage(rmt.Description, ...)
     
  }
  this.show(Modal)
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event ModuleTypeSelelction.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (!(Confirm))
  {
    IDCollection coll of IDDocument = ReferenceModuleType.collection
    coll.restoreOriginal()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event UtentiPermessiSezione.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(Utenti.IDPanel(), ...)
//  Utenti.activeMultipleSelection = true
//  Utenti.enableMultipleSelection = true
//  Utenti.showMultipleSelection = true
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UtentiPermessiSezione.showForm(
  CdataSection section // Write a comment for this parameter or press backspace to delete this comment
)
{
  // reload cdataSectionPermessi for the section 
  section.loadCdataSectionPermessi()
  Utenti.setCollection(section.UtentiWithPermesso, true)
  this.show(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CdataConfiguration.setup(
  int:kordapp kordApp // 
)
{
  this.setSections(kordApp)
  Sezioni.showScrollbar = true
  Tipi.showScrollbar = true
  DatiPersonalizzati.showScrollbar = true
}


// ──────────────────────────────────

// ************************************************************************************************
// this procedure creates a new section and insert it into the collection inthe panel CDATASECTIONS
// ************************************************************************************************
private void CdataConfiguration.insertSection()
{
  IDCollection sections of CdataSection = Sezioni.collection
  CdataSection newSection = CdataSection.create(this.Kordapp, "Nuova sezione", "Nuova sezione", ...)
  sections.add(newSection)
  Sezioni.collection = sections
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void CdataConfiguration.setSections(
  int:kordapp kordApp // 
)
{
  this.Kordapp = kordApp
  IDCollection cdataSections of CdataSection = CdataSection.getCollection(kordApp)
  Sezioni.setCollection(cdataSections, true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CdataConfiguration.Assegnapermessisezione()
{
  CdataSection cs = Sezioni.document
  if (cs)
  {
    UtentiPermessiSezione.showForm(cs)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void CdataConfiguration.insertCFI()
{
  CdataSection section = Sezioni.document
  if (section)
  {
    IDCollection CFIInPanel of MainModuleDatoPersonalizzatoInfo = DatiPersonalizzati.collection
    string captionNewCFI = "Nuovo"
    MainModuleDatoPersonalizzatoInfo newCFI = MainModuleDatoPersonalizzatoInfo.create(section, IntegerCDataType, captionNewCFI, ...)
    CFIInPanel.add(newCFI)
    DatiPersonalizzati.collection = CFIInPanel
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event CdataConfiguration.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(Sezioni.IDPanel(), true)
  GlobalPanelOperations.enableOnlyBasicCommands(Tipi.IDPanel(), ...)
  GlobalPanelOperations.enableOnlyBasicCommands(DatiPersonalizzati.IDPanel(), true)
//  Sezioni.setCommandEnabled(Refresh, false)
//  Sezioni.setCommandEnabled(Navigate, false)
//  Sezioni.setCommandEnabled(Collapse, false)
//  Sezioni.setCommandEnabled(Cancel, true)
//  Sezioni.showStatusBar(false)
//  Sezioni.collapsable = false
//  DatiPersonalizzati.setCommandEnabled(Update, false)
//  DatiPersonalizzati.setCommandEnabled(Navigate, false)
//  DatiPersonalizzati.setCommandEnabled(Collapse, false)
//  DatiPersonalizzati.collapsable = false
}


// ──────────────────────────────────

// *********************************************************************************
// Event raised by the form object in web applications when a modal window is closed
// *********************************************************************************
event CdataConfiguration.EndModal(
  int LookupForm       // An integer that identifies the modal form that was just closed, using the Me function of the form object to make the comparison.
  boolean Result       // True if the user confirmed the choice, closing the model form using the confirmation button on the title bar; otherwise False. The form can also be closed using the form object's Cl...
  inout boolean Cancel // If set to True, any subsequent automatic processing will be canceled. In this case, the framework will not attempt to automatically transfer the data from the modal form to the call...
)
{
  if (LookupForm == UtentiPermessiSezione.me())
  {
    CdataSection cs = Sezioni.document
    IDCollection utentiWithPermesso of Utente = cs.UtentiWithPermesso
    if (Result)
    {
      cs.saveToDB(...)
    }
    else 
    {
      utentiWithPermesso.restoreOriginal()
       
    }
     
  }
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event CdataConfiguration.DatiPersonalizzati.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  switch (Command)
  {
    case Insert:
      Cancel = true
      this.insertCFI()
    break
  }
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event CdataConfiguration.Sezioni.OnChangeRow()
{
  CdataSection cs = Sezioni.document
  if (cs)
  {
    Tipi.setCollection(cs.CDATAMODULETYPETransientForPanel, true)
  }
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event CdataConfiguration.Sezioni.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  switch (Command)
  {
    case Insert:
      Cancel = true
      this.insertSection()
    break
  }
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event CliforTypes.TipiClifor.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.insert()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event CliforTypes.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(TipiClifor.IDPanel(), ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CliforTypes.insert()
{
  IDCollection tipiClifor of TipoClifor = TipiClifor.collection
  TipoClifor tc = new()
  tc.init()
  tipiClifor.add(tc)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CliforTypes.showForm()
{
   
  this.show(Popup)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event TagClifor.Tag.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.insert()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event TagClifor.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(Tag.IDPanel(), ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TagClifor.insert()
{
  IDCollection tipiCaratt of GCFTIPICARATT = Tag.collection
  GCFTIPICARATT tipoCaratt = new()
  tipoCaratt.init()
  tipiCaratt.add(tipoCaratt)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event Addresses.TipiIndirizzo.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.insert()
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void Addresses.showForm()
{
  this.show(Popup)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event TipiAnagraficaPersonale.Tipianagrafica.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.insert()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event TipiAnagraficaPersonale.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(Tipianagrafica.IDPanel(), ...)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event TipiRapporto.Tipirapporto.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.insert()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event TipiRapporto.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(Tipirapporto.IDPanel(), ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void TipiRapporto.insert()
{
  IDCollection tipiRapporto of PERTIPIRAPPORTO = Tipirapporto.collection
  PERTIPIRAPPORTO tipoRapporto = new()
  tipoRapporto.init()
  tipiRapporto.add(tipoRapporto)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event Tag.Tag.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.insert()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event Tag.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(Tag.IDPanel(), ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void Tag.insert()
{
  IDCollection tags of PERTIPICARATT = Tag.collection
  PERTIPICARATT tag = new()
  tag.init()
  tags.add(tag)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event Contratti.Contatti.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.insert()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event Contratti.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(Contatti.IDPanel(), ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Contratti.insert()
{
  IDCollection conratti of PERQUALIFICHE = Contatti.collection
  PERQUALIFICHE contratto = new()
  contratto.init()
  conratti.add(contratto)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event RolesForm.TipoPersonaleRoles.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event RolesForm.Load()
{
  // hide less common commands
  GlobalPanelOperations.enableOnlyBasicCommands(TipoPersonaleRoles.IDPanel(), ...)
   
  // hide the common commands we do not want to see
  TipoPersonaleRoles.setCommandEnabled(Insert, false)
  TipoPersonaleRoles.setCommandEnabled(Delete, false)
  TipoPersonaleRoles.setCommandEnabled(Duplicate, false)
   
  TipoPersonaleRoles.canGroup = true
  TipoPersonaleRoles.showGroups = true
  TipoPersonaleRoles.addtoGroupList(TipoPersonaleRoles.DESCRUTENTE.me(), true, ...)
  TipoPersonaleRoles.refreshGrouping()
   
  // disable the 2 lookup fields because we do not want to modify them (all records are pre loaded in this form!)
  TipoPersonaleRoles.DESCRUTENTE.setEnabled(false)
  TipoPersonaleRoles.DESCRTIPOANAGRPersonale.setEnabled(false)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DocTipiFile.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(DocTipiFile.IDPanel(), ...)
  DocTipiFile.setCommandEnabled(Duplicate, false)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event DocTipiFile.DocTipiFile.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  // on inserting we move to the last row in this specific panel
  if (Command == Insert)
  {
    Cancel = true
    this.insert()
    PanelUiTools.moveToLastRow(DocTipiFile.IDPanel())
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocTipiFile.insert()
{
  IDCollection docTipiFiles of DocTipiFile = DocTipiFile.collection
  DocTipiFile docTipiFile = new()
  docTipiFile.init()
  docTipiFiles.add(docTipiFile)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DocUbicazioniForm.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(DocUbicazioni.IDPanel(), ...)
  DocUbicazioni.setCommandEnabled(Duplicate, false)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event DocUbicazioniForm.DocUbicazioni.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    this.insertUbicazione()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocUbicazioniForm.insertUbicazione()
{
  IDCollection coll of DocUbicazioni = DocUbicazioni.collection
  DocUbicazioni du = new()
  du.init()
  coll.add(du)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DOCTIPISUPPORTOForm.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(DOCTIPISUPPORTO.IDPanel(), ...)
  DOCTIPISUPPORTO.setCommandEnabled(Duplicate, false)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event DOCTIPISUPPORTOForm.DOCTIPISUPPORTO.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    this.insertTipoSupporto()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCTIPISUPPORTOForm.insertTipoSupporto()
{
  IDCollection docTipiSupportoColl of DOCTIPISUPPORTO = DOCTIPISUPPORTO.collection
  DOCTIPISUPPORTO doctipisupporto = new()
  doctipisupporto.init()
  docTipiSupportoColl.add(doctipisupporto)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DOCTIPITAGForm.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(DOCTIPITAG.IDPanel(), ...)
  DOCTIPITAG.setCommandEnabled(Duplicate, false)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event DOCTIPITAGForm.DOCTIPITAG.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    this.insertTipoTag()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCTIPITAGForm.insertTipoTag()
{
  IDCollection dociTipiTagColl of DOCTIPITAG = DOCTIPITAG.collection
  DOCTIPITAG doctipitag = new()
  doctipitag.init()
  dociTipiTagColl.add(doctipitag)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DOCTipiDocumentoForm.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(Listtipidocumento.IDPanel(), ...)
  Listtipidocumento.setCommandEnabled(Duplicate, false)
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event DOCTipiDocumentoForm.Listtipidocumento.OnChangeRow()
{
  DOCTIPIDOCUMENTO doctipidocumento = Listtipidocumento.document
   
  if (doctipidocumento)
  {
    DetailtipidocumentoPanel.setDocument(doctipidocumento, true)
  }
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event DOCTipiDocumentoForm.Listtipidocumento.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.insertNewTipoDocumento()
    PanelUiTools.moveToLastRow(Listtipidocumento.IDPanel())
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCTipiDocumentoForm.insertNewTipoDocumento()
{
  IDCollection allTipiDocumento of DOCTIPIDOCUMENTO = Listtipidocumento.collection
  DOCTIPIDOCUMENTO dtf = new()
  dtf.init()
  allTipiDocumento.add(dtf)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DOCListeDistribuzioneForm.Load()
{
  ListaDiDistribuzione.collapsable = false
  RigaListaDistribuzionePersonale.collapsable = false
  RigaListaDistribuzioneContatto.collapsable = false
   
//  IDCollection allListe of ListaDiDistribuzione = new()
//  select into collection (allListe)
//  from 
//    ListaDiDistribuzione // master table
//  ListaDiDistribuzione.setCollection(allListe, true)
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event DOCListeDistribuzioneForm.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  SearchResult sr1 = (SearchResult)Doc
  if (Message == "setLookupResults")
  {
    SearchResult sr = (SearchResult)Doc
    if (sr)
    {
      // contatto
      if (Par4 == "contatti")
      {
         IDCollection selectedContattiIDsInSearch of IntDataType = sr1.getDataTypeCollection()
         IDCollection selectedContatti of Contatto = new()
         for each IntDataType idtc in selectedContattiIDsInSearch
         {
           Contatto c = Contatto.get(idtc.IntegerValue)
           selectedContatti.add(c)
         }
         this.addAndSaveContatti(selectedContatti)
      }
      else  // personale
      {
         IDCollection selectedPersonaleIDsInSearch of IntDataType = sr.getDataTypeCollection()
         IDCollection selectedPersonale of Personale = new()
         for each IntDataType idtc in selectedPersonaleIDsInSearch
         {
           Personale p = Personale.getFromDB(idtc.IntegerValue, ...)
           selectedPersonale.add(p)
         }
         this.addAndSavePersonale(selectedPersonale)
      }
    }
  }
   
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event DOCListeDistribuzioneForm.ListaDiDistribuzione.OnChangeRow()
{
   
   
//  ListaDiDistribuzione ldd = ListaDiDistribuzione.document
//   
//  if (ldd)
//  {
//    RigaListaDistribuzionePersonale.setCollection(ldd.RigaListaDistribuzionePersonale, true)
//    RigaListaDistribuzioneContatto.setCollection(ldd.RigaListaDistribuzioneContatto, true)
//  }
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event DOCListeDistribuzioneForm.ListaDiDistribuzione.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.AggiungiListaDistribuzione()
  }
  if (Command == Delete)
  {
    Cancel = true
    UITools.displayNotImplementedMessage()
  }
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event DOCListeDistribuzioneForm.RigaListaDistribuzionePersonale.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
   
  if (Command == Insert)
  {
    Cancel = true
    this.AggiungiPersonale()
  }
  if (Command == Delete)
  {
    Cancel = true
    UITools.displayNotImplementedMessage()
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event DOCListeDistribuzioneForm.RigaListaDistribuzionePersonale.OnDynamicProperties()
{
  RigaListaDistribuzionePersonale rldp = RigaListaDistribuzionePersonale.document
  if (rldp)
  {
    Personale p = rldp.getPersonale()
    if (p.STATO != Attivo)
    {
      int redColor = RGBColor(255, 0, 0, ...)
      RigaListaDistribuzionePersonale.RecipientDescription.textColor = redColor
    }
  }
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event DOCListeDistribuzioneForm.RigaListaDistribuzioneContatto.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.AggiungiContatto()
  }
  if (Command == Delete)
  {
    Cancel = true
    UITools.displayNotImplementedMessage()
  }
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event DOCListeDistribuzioneForm.RigaListaDistribuzioneContatto.OnChangeRow()
{
  RigaListaDistribuzioneContatto rldp = RigaListaDistribuzioneContatto.document
  if (rldp)
    this.forceOnlyEmailAndCartaceaInDropDown()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCListeDistribuzioneForm.addAndSavePersonale(
  IDCollection personale of Personale // Write a comment for this parameter or press backspace to delete this comment
)
{
  ListaDiDistribuzione ldd = ListaDiDistribuzione.document
   
  IDCollection rigaListaDistribuzionePersonale of RigaListaDistribuzionePersonale = RigaListaDistribuzionePersonale.collection
  if (ldd)
  {
    for each Personale p in personale
    {
      RigaListaDistribuzionePersonale rldp = RigaListaDistribuzionePersonale.create(ldd.IDLISTADISTRIB, p.IDDIPENDENTE)
      rigaListaDistribuzionePersonale.add(rldp)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCListeDistribuzioneForm.AggiungiPersonale()
{
  if (ListaDiDistribuzione.document)
  {
    IDArray personaleToBeExcluded = new()
     
    IDCollection coll of RigaListaDistribuzionePersonale = RigaListaDistribuzionePersonale.collection
     
    for each RigaListaDistribuzionePersonale rldp in coll
    {
      personaleToBeExcluded.addValue(rldp.IDDIPENDENTE)
    }
    LookupHelper lh = LookupHelper.create(this.IDForm(), Personale, true, null, ..., personaleToBeExcluded)
    lh.displayLookup()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCListeDistribuzioneForm.AggiungiListaDistribuzione()
{
  ListaDiDistribuzione ldd = ListaDiDistribuzione.create("Nuova Lista Di Distribuzione")
  IDCollection coll of ListaDiDistribuzione = ListaDiDistribuzione.collection
   
  coll.add(ldd)
  PanelUiTools.moveToLastRow(ListaDiDistribuzione.IDPanel())
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCListeDistribuzioneForm.AggiungiContatto()
{
  if (ListaDiDistribuzione.document)
  {
    IDArray contattiToBeExcluded = new()
     
    IDCollection coll of RigaListaDistribuzioneContatto = RigaListaDistribuzioneContatto.collection
     
    for each RigaListaDistribuzioneContatto rldc in coll
    {
      contattiToBeExcluded.addValue(rldc.IDCONTATTO)
    }
     
    LookupHelper lh = LookupHelper.create(this.IDForm(), ClientiFornitori, true, null, ..., contattiToBeExcluded, Contatto.className(...))
    lh.displayLookup()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCListeDistribuzioneForm.addAndSaveContatti(
  IDCollection contatto of Contatto // Write a comment for this parameter or press backspace to delete this comment
)
{
  ListaDiDistribuzione ldd = ListaDiDistribuzione.document
   
  IDCollection rigaListaDistribuzioneContatto of RigaListaDistribuzionePersonale = RigaListaDistribuzioneContatto.collection
  if (ldd)
  {
    for each Contatto c in contatto
    {
      RigaListaDistribuzioneContatto rldp = RigaListaDistribuzioneContatto.create(ldd.IDLISTADISTRIB, c.IDCONTATTO, c.IDCONTO)
      rigaListaDistribuzioneContatto.add(rldp)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCListeDistribuzioneForm.deleteListaDiDistribuzione()
{
  ListaDiDistribuzione ldd = ListaDiDistribuzione.document
  if (ldd)
  {
    ldd.deleted = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCListeDistribuzioneForm.DeleteRigaListaDiDistribuzionePersonale()
{
  RigaListaDistribuzionePersonale ldd = RigaListaDistribuzionePersonale.document
  if (ldd)
  {
    ldd.deleted = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCListeDistribuzioneForm.deleteRigaListaDiDistribuzioneContatto()
{
  RigaListaDistribuzioneContatto ldd = RigaListaDistribuzioneContatto.document
  if (ldd)
  {
    ldd.deleted = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DOCListeDistribuzioneForm.RimuoviPersonaleChiuso()
{
  ListaDiDistribuzione ldd = ListaDiDistribuzione.document
  if (ldd)
  {
    ldd.removeInactivePersonaleFromAllListeDistribuzione()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DOCListeDistribuzioneForm.forceOnlyEmailAndCartaceaInDropDown()
{
  RigaListaDistribuzioneContatto.TIPODISTRIBUZIONE.clearValueList()
  RigaListaDistribuzioneContatto.TIPODISTRIBUZIONE.addValueListItem(E-Mail, decode(E-Mail, TipiDistribuzione), ...)
  RigaListaDistribuzioneContatto.TIPODISTRIBUZIONE.addValueListItem(Cartacea, decode(Cartacea, TipiDistribuzione), ...)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event ApplicazioniSubform.Load()
{
  MenuFoldersCommandset.visible = true
}


// ──────────────────────────────────

// *********************************************************************************
// Event raised by the form object in web applications when a modal window is closed
// *********************************************************************************
event ApplicazioniSubform.EndModal(
  int LookupForm       // An integer that identifies the modal form that was just closed, using the Me function of the form object to make the comparison.
  boolean Result       // True if the user confirmed the choice, closing the model form using the confirmation button on the title bar; otherwise False. The form can also be closed using the form object's Cl...
  inout boolean Cancel // If set to True, any subsequent automatic processing will be canceled. In this case, the framework will not attempt to automatically transfer the data from the modal form to the call...
)
{
  if (LookupForm == IconPicker.me())
  {
    MenuItem mi = menuitemspanel.document
    mi.ICONINDEX = QappCore.IconFactory.getIndexFromFontAwesome(IconPicker.selectionpanel.chosenIcon)
     
    MenuFolder mf = MenuFolderspanel.document
    mf.ICONINDEX = QappCore.IconFactory.getIndexFromFontAwesome(IconPicker.selectionpanel.chosenIcon)
  }
   
}


// ──────────────────────────────────

// *********************************************************************
// The Tabbed View object raises this event when the active page changes
// *********************************************************************
event ApplicazioniSubform.ApplicazioniAppManTabbedView.ChangePage(
  int PreviousPage     // An integer representing the index of the page previously selected in the Tabbed View. Use the Me function of the panel or visual object contained in the Tabbed View to make the comp...
  inout boolean Cancel // If set to True, cancels the page change.
)
{
  if (ApplicazioniAppManTabbedView.selectedPage() == MenuFolderspanel.me() and PreviousPage == menuitemspanel.me())
  {
    MenuFoldersCommandset.visible = true
  }
  else 
  {
    MenuFoldersCommandset.visible = false
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ApplicazioniSubform.Nuovo()
{
  MenuFolder mf = MenuFolder.create("")
   
  IDCollection menuFolderCollection of MenuFolder = MenuFolderspanel.collection
   
  if (mf)
  {
    menuFolderCollection.add(mf)
  }
  else 
  {
    UIBusinessLogic.DTTLogMessage("Errore nella creazione della nuova Cartella Menu.", ..., DTTError)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ApplicazioniSubform.Elimina()
{
  MenuFolderspanel.deleteRow()
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void Reparti.Elimina()
{
  Reparti.deleteRow()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void Reparti.Nuovo()
{
  IDCollection allReparti of Reparto = Reparti.collection
   
  Reparto nuovoReparto = Reparto.create("")
   
  if (nuovoReparto)
  {
    allReparti.add(nuovoReparto)
  }
  else 
  {
    UIBusinessLogic.DTTLogMessage("Errore nella creazione del nuovo Reparto.", ..., DTTError)
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event Privilegi.Load()
{
  GlobalPanelOperations.enableOnlyBasicCommands(Filters.IDPanel(), ...)
  GlobalPanelOperations.enableOnlyBasicCommands(PrivilegiPanel.IDPanel(), ...)
   
  // initialize the value (for query)
   
  this.initializeFilterParams()
  this.updatePrivilegiCollection()
   
  PrivilegiPanel.listQBE = false
   
  Privilegio p = new()
  int executeIxd = p.getPropertyIndex("PRIVEXECUTE", true, true, true, true)
  int insertIdx = p.getPropertyIndex("PRIVINSERT", true, true, true, true)
  int updateIdx = p.getPropertyIndex("PRIVUPDATE", true, true, true, true)
  int deleteIdx = p.getPropertyIndex("PRIVDELETE", true, true, true, true)
  int printIdx = p.getPropertyIndex("PRIVPRINT", true, true, true, true)
   
  int exportIdx = p.getPropertyIndex("PRIVEXPORT", true, true, true, true)
  int emailIdx = p.getPropertyIndex("PRIVEMAIL", true, true, true, true)
  int pers1Idx = p.getPropertyIndex("PRIVPERS1", true, true, true, true)
  int pers2Idx = p.getPropertyIndex("PRIVPERS2", true, true, true, true)
  int pers3Idx = p.getPropertyIndex("PRIVPERS3", true, true, true, true)
  int pers4Idx = p.getPropertyIndex("PRIVPERS4", true, true, true, true)
  int pers5Idx = p.getPropertyIndex("PRIVPERS5", true, true, true, true)
  int datiPIdx = p.getPropertyIndex("PRIVDATIP", true, true, true, true)
   
  this.UIAutomation = UIAutomation.Create(PrivilegiPanel.IDPanel())
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVEXECUTE.me(), executeIxd)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVINSERT.me(), insertIdx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVUPDATE.me(), updateIdx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVDELETE.me(), deleteIdx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVEXPORT.me(), exportIdx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVEXPORT.me(), printIdx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVEMAIL.me(), emailIdx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVDATIP.me(), datiPIdx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVPERS1.me(), pers1Idx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVPERS2.me(), pers2Idx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVPERS3.me(), pers3Idx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVPERS4.me(), pers4Idx)
  this.UIAutomation.mapUIField(PrivilegiPanel.PRIVPERS5.me(), pers5Idx)
   
//  // suggestion to how to automaze the lines above
//  IDDocumentStructure idds = p.getStructure()
//   
//  for (int i = 0; i < idds.getPropertyCount(); i = i + 1)
//  {
//    IDPropertyDefinition idpd = idds.getPropertyDefinition(i)
//     
//    if (!(idpd))
//    {
//      continue 
//    }
//    UIBusinessLogic.DTTLogMessage(idpd.DBCode, ...)
//  }
//   
//  IDPanel idp = PrivilegiPanel.IDPanel()
//  for (int i1 = 0; i1 < idp.fieldsCount(); i1 = i1 + 1)
//  {
//    UIBusinessLogic.DTTLogMessage(idp.getFieldDBCode(i1), ...)
//  }
   
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event Privilegi.PrivilegiPanel.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  if (Button == Right and Row > -1 and Column > 4)
  {
    this.UIAutomation.alignClickCoordinates(Row, Column)
    popupMenu.openPopupXY(XB, YB)
  }
}


// ──────────────────────────────────

// ******************************************************************************************
// Event raised by the panel prior to inserting the data for a new panel row in the database.
// ******************************************************************************************
event Privilegi.PrivilegiPanel.BeforeInsert(
  inout boolean Cancel // If set to True, the data for this row is not inserted. The saving step for other rows proceeds as normal.
)
{
  Cancel = PrivilegiPanel.document == null
}


// ──────────────────────────────────

// *****************************************************************************************
// update data on the Privilegi panel checking if there are changes that the user would save
// *****************************************************************************************
private void Privilegi.updatePrivilegiCollection()
{
  IDCollection collPrivilegi of Privilegio = PrivilegiPanel.collection
  if (collPrivilegi and collPrivilegi.isModified() and collPrivilegi.count() > 0)
  {
    int userAnswer = UIBusinessLogic.messageConfirmEx("Ci sono modifiche, vuoi salvarle?", "Sì;No")
    switch (userAnswer)
    {
      case 1:
         PrivilegiPanel.updateData()
         this.restoreFilterStatus()
      break
      case 2:
         PrivilegiPanel.undoChanges()
         this.loadData()
         this.storeFilterStatus()
      break
    }
  }
  else 
  {
    this.loadData()
    this.storeFilterStatus()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Privilegi.loadData()
{
  IDCollection filteredCollection of Privilegio = Privilegio.getCollectionOfPrivilegi(Filters.IdUtenteIMDBFilter, Filters.IdApplicazioneIMDBFilter)
  PrivilegiPanel.setCollection(filteredCollection, true)
  PrivilegiPanel.actualPosition = 1
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Privilegi.initializeFilterParams()
{
  // initialize the value (for query)
  Filters.IdUtenteIMDBFilter = QappCore.Loggeduser.IDUTENTE
  Filters.IdApplicazioneIMDBFilter = null
   
  // initialize the field (for UI)
  IMDBFilter.IdUtente = QappCore.Loggeduser.IDUTENTE
  IMDBFilter.IdApplicazione = null
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Privilegi.storeFilterStatus()
{
  this.PreviouslySearchContent.IDUTENTE = Filters.IdUtenteIMDBFilter
  this.PreviouslySearchContent.IDAPPLICAZIONE = Filters.IdApplicazioneIMDBFilter
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Privilegi.restoreFilterStatus()
{
  Filters.IdUtenteIMDBFilter = this.PreviouslySearchContent.IDUTENTE
  Filters.IdApplicazioneIMDBFilter = this.PreviouslySearchContent.IDAPPLICAZIONE
  //  
  // initialize the field (for UI)
  IMDBFilter.IdUtente = this.PreviouslySearchContent.IDUTENTE
  IMDBFilter.IdApplicazione = this.PreviouslySearchContent.IDAPPLICAZIONE
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Privilegi.SelezionaTutti()
{
  this.UIAutomation.applyValue(Yes)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Privilegi.DeselezionaTutti()
{
  this.UIAutomation.applyValue(No)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Privilegi.MostraSoloDeselezionati()
{
  this.UIAutomation.filterByValue("N")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Privilegi.MostraSoloAbilitati()
{
  this.UIAutomation.filterByValue(Yes)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void Privilegi.MostraTutti()
{
  this.UIAutomation.removeFilters()
   
  // restore the original sorting criteria
  Privilegio p = new()
  int i = p.getPropertyIndex("IDAPPLICAZIO", true, true, true, true)
  IDCollection coll of Privilegio = PrivilegiPanel.collection
  coll.addSortCriteria(i)
  coll.doSort()
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event Utenti.Load()
{
  Utenti.collapsable = false
  Utenti.collapsed = false
   
  Utenti.IDUTENTE.setEnabled(false)
  Utenti.setErrorMode(Message, Message, Message, Message)
   
  GlobalPanelOperations.enableOnlyBasicCommands(Utenti.IDPanel(), ...)
}


// ──────────────────────────────────

// *********************************************************************************
// Event raised by the form object in web applications when a modal window is closed
// *********************************************************************************
event Utenti.EndModal(
  int LookupForm       // An integer that identifies the modal form that was just closed, using the Me function of the form object to make the comparison.
  boolean Result       // True if the user confirmed the choice, closing the model form using the confirmation button on the title bar; otherwise False. The form can also be closed using the form object's Cl...
  inout boolean Cancel // If set to True, any subsequent automatic processing will be canceled. In this case, the framework will not attempt to automatically transfer the data from the modal form to the call...
)
{
  if (LookupForm == CreateUser.me())
  {
    if (Result)
    {
      Utenti.refreshQuery()
    }
  }
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event Utenti.Utenti.OnChangeRow()
{
   
  Utente u = Utenti.document
  int idxReimpostPassword = Reimpostapassword.getIndex()
  if (u)
  {
    if (u.isLdapUser())
    {
      UtentiCommandset.setCommandVisible(idxReimpostPassword, false)
    }
    else 
    {
      UtentiCommandset.setCommandVisible(idxReimpostPassword, true)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void Utenti.deleteUser()
{
  Utente u = Utenti.document
  if (u)
  {
    int response = UIBusinessLogic.messageConfirmEx(formatMessage("Vuoi cancellare l'utente <b>|1</b>", u.DESCRUTENTE, ...), "Si;No")
    if (response == 1)
    {
      boolean userIsDeleteable = u.isDeletable()
      if (userIsDeleteable)
      {
         u.deleted = true
         u.saveToDB(...)
      }
      else 
      {
         UIBusinessLogic.messageBox(formatMessage("l'utente |1 <b>non può essere eliminato</b> poiché è stato utilizzato in altri moduli", u.Username, ...))
      }
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void Utenti.Reimpostapassword()
{
  Utente u = Utenti.document
  if (u)
  {
    boolean validUser = u.validate(...)
    if (!(validUser))
    {
      UIBusinessLogic.messageBox("Impossibile modificare la password, controllare gli errori")
      return 
    }
     
    boolean passwordChanged = u.performSqlServerResetUserPassword(...)
     
    if (passwordChanged)
    {
      UIBusinessLogic.messageBox(formatMessage("La password per l'utente |1 è ora '|2'", u.Username, lower(u.Username), ...))
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void Utenti.SMTP()
{
  Utente u = Utenti.document
  if (u)
  {
    SMTPSettings.showForm(u)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void Utenti.newUtente()
{
  CreateUser.showForm(Modal)
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void CalendarAltriUtenti.FilterByUser()
{
  this.SelectedUser = ByUserFilter.IDUTENTE
  this.SelectedCalendarOf = 0
   
  // filter if a user is selected
  if (this.SelectedUser > 0)
  {
    IDCollection resultUserBased of DisposizioneCalendarPrivilegi = new()
    select into collection (resultUserBased)
    from 
      DisposizioneCalendarPrivilegi // master table
    where
      IDUTENTE == this.SelectedUser
     
    Calendarpermissiontable.setCollection(resultUserBased, true)
    return 
  }
   
   
  // no filter set
  IDCollection resultNoFilter of DisposizioneCalendarPrivilegi = new()
  select into collection (resultNoFilter)
  from 
    DisposizioneCalendarPrivilegi // master table
   
  Calendarpermissiontable.setCollection(resultNoFilter, true)
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void CalendarAltriUtenti.FilterByCalendarOf()
{
  this.SelectedUser = 0
  this.SelectedCalendarOf = CalendarioOfFilter.IDUTENTE
   
  // filter if calendar of is selected
  if (this.SelectedCalendarOf > 0)
  {
    IDCollection calendarOfResults of DisposizioneCalendarPrivilegi = new()
    select into collection (calendarOfResults)
    from 
      DisposizioneCalendarPrivilegi // master table
    where
      IDALTROUTENTE = this.SelectedCalendarOf
     
    Calendarpermissiontable.setCollection(calendarOfResults, true)
    return 
  }
   
   
  // no filter set
  IDCollection resultNoFilter of DisposizioneCalendarPrivilegi = new()
  select into collection (resultNoFilter)
  from 
    DisposizioneCalendarPrivilegi // master table
   
  Calendarpermissiontable.setCollection(resultNoFilter, true)
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void SMTPSettings.MailDiTest()
{
  EmailInput.showForm()
   
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void SMTPSettings.Save()
{
  SMTPSettings.updateData()
  NGTUSERSMTP smtpSettings = SMTPSettings.document
  if (!(smtpSettings.isInError(...)))
    this.close(true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void SMTPSettings.Close()
{
  this.close(false)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void SMTPSettings.sendTestEmail(
  string emalTo // 
)
{
  Mailer m = new()
  m.fromAddress = "noreply@qualibus.it"
  m.subject = "Prova la posta dal pannello di configurazione SMTP."
  m.body = "Per favore ignora questa mail, questa è una mail di prova dal pannello di configurazione SMTP."
  m.addTO:address(emalTo)
  try 
  {
    m.setRELAYServer(SMTPSettings.HOST, SMTPSettings.PORT, "", SMTPSettings.SMTPUSERNAME, SMTPSettings.UnencryptedPassword, SMTPSettings.SECURETYPES)
    m.sendMail()
    UIBusinessLogic.messageBox("Email di prova inviata con successo!!")
  }
  catch 
  {
    string exceptionDetails = errorMessage()
     
    UIBusinessLogic.messageBox(formatMessage("Impossibile inviare l'e-mail all'indirizzo |1 (dettagli: |2)", emalTo, exceptionDetails, ...))
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event SMTPSettings.Load()
{
  SMTPSettings.collapsable = false
  SMTPSettings.collapsed = false
}


// ──────────────────────────────────

// *********************************************************************************
// Event raised by the form object in web applications when a modal window is closed
// *********************************************************************************
event SMTPSettings.EndModal(
  int LookupForm       // An integer that identifies the modal form that was just closed, using the Me function of the form object to make the comparison.
  boolean Result       // True if the user confirmed the choice, closing the model form using the confirmation button on the title bar; otherwise False. The form can also be closed using the form object's Cl...
  inout boolean Cancel // If set to True, any subsequent automatic processing will be canceled. In this case, the framework will not attempt to automatically transfer the data from the modal form to the call...
)
{
  if (LookupForm == EmailInput.me())
  {
    if (Result)
    {
      string emailTo = EmailInput.EmailInput.EmailNewPanel
      this.sendTestEmail(emailTo)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EmailInput.ButtonOK()
{
  this.close(true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EmailInput.ButtonAnnulla()
{
  this.close(false)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EmailInput.showForm()
{
  this.show(Modal)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CreateUser.showForm(
  int:openAs OpenAs // Write a comment for this parameter or press backspace to delete this comment
)
{
  UserCreation uc = UserCreation.create(createNewEmployee)
  CreateUser.setDocument(uc, true)
  this.show(OpenAs)
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event CreateUser.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm)
  {
    CreateUser.updateData()
     
     
    // in case of document errors we do not want to close the form
     
    UserCreation uc = CreateUser.document
     
    UIBusinessLogic.DTTLogMessage(formatMessage("uc object valid: |1", uc.valid, ...), ...)
     
    // this validation won't check for uniqueness of username in DB (since "utente Just Been succesfully Inserted in DB" private property is used to mark succesful insertion of new user in db)
    boolean docIsValid = uc.validate(Complete, ...)
     
    UIBusinessLogic.DTTLogMessage(formatMessage("uc object manualy validted: |1", docIsValid, ...), ...)
     
    UIBusinessLogic.DTTLogMessage(formatMessage("username: |1", uc.Username, ...), ...)
     
     
     
    if (!(docIsValid))
    {
      Cancel = true
    }
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event CreateUser.Load()
{
  CreateUser.collapsable = false
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event CreateUser.CreateUser.OnDynamicProperties()
{
  UserCreation uc = CreateUser.document
  if (uc)
  {
    CreateUser.COGNOME.setEnabled(uc.CreationMode == createNewEmployee)
    CreateUser.NOME.setEnabled(uc.CreationMode == createNewEmployee)
    CreateUser.IdExistingPersonale.setVisible(uc.CreationMode == useExistingEmployee)
     
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CreateUser.ButtonConferma()
{
  UserCreation uc = CreateUser.document
   
  // this validation won't check for uniqueness of username in DB (since "utente Just Been succesfully Inserted in DB" private property is used to mark succesful insertion of new user in db)
  boolean docIsValid = uc.validate(Complete, ...)
   
  if (docIsValid)
  {
    uc.saveToDB(...)
    this.close(...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CreateUser.ButtonAnnulla()
{
  UserCreation uc = CreateUser.document
   
  if (uc.isModified(...))
  {
    int i = UIBusinessLogic.messageConfirmEx("Annullando perderai le modifiche fatte, confermi?", "Sì;No")
    if (i == 1)
    {
      this.close(...)
    }
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event OpzioniEsiti.Load()
{
  Esitievento.collapsable = false
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event OpzioniEsiti.Esitievento.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  if (Button == Right)
  {
    EventoEsiti ee = Esitievento.document
    if (ee)
    {
      buttonscommandset.openPopupXY(XB, YB)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void OpzioniEsiti.aggiungi()
{
  IDCollection allEventoEsiti of EventoEsiti = Esitievento.collection
  EventoEsiti newlyCreatedEsito = EventoEsiti.create("Nuovo esito")
   
  if (newlyCreatedEsito)
  {
    allEventoEsiti.add(newlyCreatedEsito)
  }
  else 
  {
    UIBusinessLogic.messageBox("Errore nella creazione del nuovo esito.")
  }
   
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************************
// Event raised by the panel when a field is activated.
// ****************************************************
event OpzioniMainPageForm.MainPage.OnActivateField(
  int FieldIndex       // An integer representing the panel field that has been activated. It should be compared with the Me property of the panel field.
  inout boolean Cancel // This can be set to True to cancel activation by any activation object associated with the panel field.
)
{
  IDPanel idp = MainPage.IDPanel()
  string code = idp.findFieldCode(FieldIndex)
  this.moveToRequestedSubform(code)
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event OpzioniMainPageForm.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  this.handleFormClosure(Cancel)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void OpzioniMainPageForm.ShowForm(
  MainPageFormConfiguration configuration // 
)
{
  this.setObjectTag("subform", configuration)
  this.MainPageFormConfiguration = configuration
  this.caption = this.MainPageFormConfiguration.getCaption()
  this.MainPageFormConfiguration.computeTabViewMainPageBuilder(MainPage.IDPanel())
   
  if (this.MainPageFormConfiguration.TabViewMainPageBuilder)
  {
    this.MainPageFormConfiguration.setupButtons()
    this.moveToMainPage()
    this.show(MDI)
  }
  else 
  {
    this.close(...)
  }
}


// ──────────────────────────────────

// *************************************************************************************************************
// add a instance of a subform to the tabbed view, set the second parameter to true to make the subform selected
// *************************************************************************************************************
private void OpzioniMainPageForm.moveToRequestedSubform(
  string code // 
)
{
  IDForm subform = prepareSubFormInstance(code)
  if (subform)
  {
    int nextTVPosition = OpzioniTabbedView.getFormPageIndex(subform)
    OpzioniTabbedView.selectPage(nextTVPosition)
    Back.visible = true
    Save.visible = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private IDForm OpzioniMainPageForm.prepareSubFormInstance(
  string code // 
)
{
  IDForm requestedSubform = null
  if (this.OpenedTabs.containsKey(code))
  {
    requestedSubform = (IDForm)this.OpenedTabs.getObject(code)
  }
  else 
  {
    requestedSubform = this.MainPageFormConfiguration.getSubformInstance(code)
    if (requestedSubform)
    {
      this.OpenedTabs.setObject(code, requestedSubform)
      OpzioniTabbedView.addForm(requestedSubform)
    }
  }
  this.SelectedCurrentForm = requestedSubform
  return requestedSubform
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void OpzioniMainPageForm.moveToMainPage()
{
  int mainPageIndex = OpzioniTabbedView.getPageIndex(MainPage.me()) + 1
  OpzioniTabbedView.selectPage(mainPageIndex)
  Back.visible = false
  Save.visible = false
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void OpzioniMainPageForm.Save()
{
  if (this.SelectedCurrentForm)
  {
    UIBusinessLogic.DTTLogMessage(this.SelectedCurrentForm.caption, ...)
     
    int panelCount = this.SelectedCurrentForm.getPanelsCount()
     
    for (int i = 0; i < panelCount; i = i + 1)
    {
      IDPanel idp = this.SelectedCurrentForm.getPanel(i)
      if (idp)
      {
         IDCollection documents of IDDocument = idp.collection
         if (documents)
         {
           boolean errorFound = GlobalPanelOperations.AnyDocumentOnPanelHasValidationError(idp)
           if (errorFound)
           {
             ErrorReporter.showErrorsOfDocumentCollection(documents)
           }
           else 
           {
             documents.saveToDB(...)
           }
         }
      }
    }
     
    // toast notification on SAVE
    string tooltipHTMLTitle = "<div class='saveTooltip'>Salvato <i class='fa fa-save'></i></div>"
    UIBusinessLogic.showTooltip(tooltipHTMLTitle, ..., 0, 3000)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void OpzioniMainPageForm.Back()
{
  int mainPageIndex = OpzioniTabbedView.getPageIndex(MainPage.me()) + 1
  int currentPageIndex = OpzioniTabbedView.selectedPage()
  if (mainPageIndex == currentPageIndex)
  {
    this.close(true)
  }
  else 
  {
    boolean atLeastOnePanelIsModified = false
    IDArray ida = this.OpenedTabs.getKeys()
    for (int i = 0; i < ida.length(); i = i + 1)
    {
      IDForm idf = (IDForm)this.OpenedTabs.getObject(ida.getValue(i))
      boolean pendingChangesOperationResult = GlobalPanelOperations.executeOperation(pendingChanges, idf)
      atLeastOnePanelIsModified = atLeastOnePanelIsModified or pendingChangesOperationResult == true
      if (atLeastOnePanelIsModified)
      {
         break 
      }
    }
    if (atLeastOnePanelIsModified)
    {
      int response = UIBusinessLogic.messageConfirmEx("Ci sono <font color="purple"><b>modifiche non salvate</b></font>, tornare indietro?", "Sì;No")
      if (response == 1)
      {
         this.moveToMainPage()
         IDPanel idp = this.SelectedCurrentForm.getPanel(0)
         if (idp)
         {
           idp.undoChanges()
         }
      }
    }
    else 
    {
      this.moveToMainPage()
    }
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ************************************************************
// this procedure handles the user response to the form closure
// ************************************************************
private void OpzioniMainPageForm.handleUserResponse(
  inout boolean cancelFormClosure // 
)
{
  int response = UIBusinessLogic.messageConfirmEx(formatMessage("Ci sono <font color="purple"><b>modifiche non salvate</b></font>, chiudere <i>|1</i>?", this.caption, ...), "Sì;No")
  if (this.getTag("waitingResult") == true)
  {
    if (response == 2)
    {
      cancelFormClosure = true
    }
  }
   
   
  if (response == null)
  {
    this.setTag("waitingResult", true)
    cancelFormClosure = true
  }
  else 
  {
    this.setTag("waitingResult", false)
  }
}


// ──────────────────────────────────

// *****************************************************************************
// this form allows the mulitple selection of users that have a linked personale
// *****************************************************************************
public void EmployeesSelection.showForm(
  IDCollection resultingUtenti of Utente // 
)
{
  PanelTools.EnableMultiselection(utenti.IDPanel(), true, true)
  this.show(...)
  UtentiFocusTimer.enabled = true
  Ricerca.Searchstring = ""
  this.bringToFront()
  this.setObjectTag("result", resultingUtenti)
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event EmployeesSelection.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm)
  {
    IDCollection result of Utente = this.getObjectTag("result")
    IDCollection coll of Utente = utenti.collection
    for each Utente u in coll
    {
      if (u.selected)
      {
         result.add(u)
      }
    }
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event RegistryTypeSelection.Load()
{
  this.hasDebugButton = false
  TypeSelection.locked = true
  TypeSelection.Description.setEnabled(false)
  TypeSelection.ID.setEnabled(false)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void RegistryTypeSelection.setupTable(
  int:kordapp kord // Write a comment for this parameter or press backspace to delete this comment
)
{
  switch (kord)
  {
    case ClientiFornitori:
      for each row (readonly)
      {
         select
           DESCRTIPOCONTOGCFTIPICONTO = DESCRTIPOCONTO
           IDTIPOCONTOGCFTIPICONTO = IDTIPOCONTO
         from 
           GCFTIPICONTO // master table
          
         insert values into Types
           set Description = DESCRTIPOCONTOGCFTIPICONTO
           set ID = IDTIPOCONTOGCFTIPICONTO
      }
    break
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event FluidFileUpload.Load()
{
  this.hasConfirmButton = false
  int maxAllowedSizeInMB = DOCPARAMETRI.getMaxAllowedSizeUploadFile()
  panel.BlobData.setBlobSize(maxAllowedSizeInMB / 2, maxAllowedSizeInMB, ...)
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event FluidFileUpload.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm and panel.document)
  {
    DocumentUploadHelper d = panel.document
    if (d and d.BlobData != null)
    {
      d.computeBlob()
    }
    else 
    {
      Cancel = true
      UIBusinessLogic.messageBox("Non e' stato caricato nessun file. Carica un file e riprova.")
    }
  }
}


// ──────────────────────────────────

// **************************************************************************************************************************
// Event raised by the panel after saving the file uploaded by the user to the database or deleting the contents of the blob.
// **************************************************************************************************************************
event FluidFileUpload.panel.AfterBLOBUpdate(
  int Column       // An integer specifying which panel field is involved in the update or delete operation. It should be compared with the Me function of the panel fields.
  int Size         // Size of the uploaded file in bytes, or -1 if the contents of the blob have been deleted.
  string Extension // A string containing the extension of the file being loaded.
)
{
  DocumentUploadHelper duh = panel.document
  if (duh)
  {
    duh.setExtension(Extension)
  }
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FluidFileUpload.showForm(
  DocumentUploadHelper duh  // 
  string expectedExtensions // 
)
{
  panel.setDocument(duh, ...)
  panel.BlobData.text = "prova<br>prova!"
  panel.Description.setEnabled(duh.EnableDescription)
   
  if (expectedExtensions == "")
  {
    duh.initializeDocTipiFileSupportExtensions()
  }
  string expectedExtension = duh.supportedExtensionsAsFileTypesString()
  UIBusinessLogic.DTTLogMessage(expectedExtension, ...)
   
  // second parameter is not supported anymore in new browsers
  panel.BlobData.setFileTypes(expectedExtension, "")
   
  this.show(Modal)
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void FluidFileUpload.ConfirmButton()
{
  this.close(true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocumentiSearchOBSOLETE.showform(
  optional boolean searchAllDocuments = 0 // 
)
{
  this.SearchAllDocuments = searchAllDocuments
  this.show(Modal)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DocumentiSearchOBSOLETE.Load()
{
  Search.SearchString = ""
   
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event DocumentiSearchOBSOLETE.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm)
  {
    Documento document = Documenti.document
    if (document)
    {
      string errorMessage = ""
      if (!(document.extensionSupportedByNuovoDaTemplate(errorMessage)))
      {
         Cancel = true
         UIBusinessLogic.messageBox(errorMessage)
      }
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AssegnaRuoli.showForm(
  Cartella cartella // Write a comment for this parameter or press backspace to delete this comment
)
{
  this.Cartella = cartella
  this.Cartella.loadPermessi()
  DOCPERMESSI.setCollection(this.Cartella.DOCPERMESSI, true)
  this.caption = formatMessage("Assegna Ruoli (|1)", cartella.DESCRCARTELLA, ...)
  DOCPERMESSI.setCanUpdate(false)
  AggiungiUtente.visible = false
   
  if (QappCore.Loggeduser.hasSpecificPrivilegeForKordApp(Documenti, Pers1) or cartella.isLoggedUserFolderAdmin())
  {
    DOCPERMESSI.setCanUpdate(true)
    AggiungiUtente.visible = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AssegnaRuoli.AggiungiUtente()
{
  IDCollection utentiToShow of Utente = this.Cartella.getUtentiWithPermessiFromPadre()
   
  IDCollection utentiToBeExcluded of Utente = new()
   
  IDCollection coll of DOCPERMESSI = this.Cartella.DOCPERMESSI
   
  for each DOCPERMESSI dp in coll
  {
    Utente u = new()
    u.IDUTENTE = dp.IDUTENTE
    utentiToBeExcluded.add(u)
  }
   
  for each Utente us in utentiToShow
  {
    for each Utente ue in utentiToBeExcluded
    {
      if (us.IDUTENTE == ue.IDUTENTE)
      {
         us.deleted = true
      }
    }
  }
   
  utentiToShow.removeDeleted()
   
  UtenteLookupForDocpermessi.ShowForm(this, utentiToBeExcluded, utentiToShow)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AssegnaRuoli.addUsers(
  IDCollection users of Utente // 
)
{
  IDCollection docPermessi of DOCPERMESSI = DOCPERMESSI.collection
  for each Utente u in users
  {
    DOCPERMESSI docpermesso = DOCPERMESSI.create(u, this.Cartella)
    docPermessi.add(docpermesso)
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event AssegnaRuoli.Load()
{
  this.closeOnSelection = false
  DOCPERMESSI.listQBE = No
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event AssegnaRuoli.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm)
  {
    string errorMessage = ""
    this.Cartella.handlePermessiChanges(errorMessage, Cancel, SaveToDB)
     
    if (errorMessage != null)
    {
      this.showMessage(Popup, errorMessage, ...)
    }
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event AssegnaRuoli.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "NewUserAdded")
  {
    IDCollection usersToBeAdded of Utente = (IDCollection)Doc.getObjectTag("SelectedUsers")
    this.addUsers(usersToBeAdded)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UtenteLookupForDocpermessi.ShowForm(
  IDForm callerForm                         // Write a comment for this parameter or press backspace to delete this comment
  IDCollection utenteToBeExcluded of Utente // 
  IDCollection utentiToShow of Utente       // 
)
{
  this.CallerForm = callerForm
  this.UtentiToBeExcluded = utenteToBeExcluded
  this.UtentiToShow = utentiToShow
  this.show(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UtenteLookupForDocpermessi.hideUtente(
  IDCollection utenteToBeHidden of Utente // Write a comment for this parameter or press backspace to delete this comment
)
{
  IDCollection utenti of Utente = Utente.collection
  for each Utente u in utenti
  {
    for each Utente u1 in utenteToBeHidden
    {
      if (u.IDUTENTE == u1.IDUTENTE)
      {
         u.hidden = true
      }
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UtenteLookupForDocpermessi.hideAllUtentiNotIn(
  IDCollection utenteToBeShow of Utente // Write a comment for this parameter or press backspace to delete this comment
)
{
  IDCollection utenti of Utente = Utente.collection
  for each Utente u in utenti
  {
    boolean found = false
    for each Utente u1 in utenteToBeShow
    {
      if (u.IDUTENTE == u1.IDUTENTE)
      {
         found = true
         break 
      }
    }
     
    if (!(found))
    {
      u.hidden = true
    }
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event UtenteLookupForDocpermessi.Load()
{
  Utente.showMultipleSelection = true
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event UtenteLookupForDocpermessi.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm)
  {
    IDCollection allUsers of Utente = Utente.collection
     
    IDCollection selectedUsers of Utente = new()
    for each Utente u in allUsers
    {
      if (u.selected)
      {
         selectedUsers.add(u)
      }
    }
    IDDocument doc = new()
    doc.setObjectTag("SelectedUsers", selectedUsers)
    this.CallerForm.sendMessage("NewUserAdded", doc, ...)
  }
}


// ──────────────────────────────────

// **********************************************************************
// Event raised by the panel after it has retrieved the master query data
// **********************************************************************
event UtenteLookupForDocpermessi.Utente.AfterFind(
  int:panelCommands Command // This was introduced in version 6.8.3060 and represents the panel command that caused the event to fire. The possible values are Find, Insert, or Refresh. Refer also to the Pane...
)
{
  if (this.UtentiToShow.count() > 0)
  {
    this.hideAllUtentiNotIn(this.UtentiToShow)
  }
  else if (AssegnaRuoli.Cartella.IDPADRE != null)
  {
    IDCollection utenti of Utente = Utente.collection
     
    for each Utente u in utenti
    {
      u.hidden = true
    }
  }
  else 
  {
    this.hideUtente(this.UtentiToBeExcluded)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocumentInserter.ButtonOK()
{
  DocumentoInserter di = DocumentoInserter.document
  if (di)
  {
    boolean isValid = di.validate(Complete, ...)
    if (!(isValid))
    {
      DocumentoInserter.showDocErrors(di, ...)
      return 
    }
     
    Documento d = di.generateDocument(true)
    d.saveToDB(...)
    this.close(false)
    this.CallerForm.sendMessage("DocumentAdded", di.Cartella, ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocumentInserter.showForm(
  IDForm callerForm             // 
  DocumentoInserter docInserter // Write a comment for this parameter or press backspace to delete this comment
  int:openAs openAs             // 
)
{
  if (docInserter)
  {
    this.CallerForm = callerForm
    DocumentoInserter.setDocument(docInserter, true)
    this.setVisibility()
    this.show(openAs)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocumentInserter.ButtonCaricafile()
{
//  UIBusinessLogic.messageBox("Questa funzionalità non è ancora supportata! ")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocumentInserter.ButtonDaaltrodoc()
{
  UIBusinessLogic.messageBox("Questa funzionalità non è ancora supportata! ")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocumentInserter.setVisibility()
{
  DocumentoInserter di = DocumentoInserter.document
  if (di)
  {
    DocumentoInserter.Approve.setVisible(di.InsertionType != WithoutFile)
    DocumentoInserter.ButtonAddFile.setVisible(di.InsertionType == FromFile)
    DocumentoInserter.Filename.setVisible(di.InsertionType == FromFile)
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DocumentInserter.Load()
{
  DocumentoInserter.ButtonAddFile.setMultiUpload(1, ...)
  DocumentoInserter.setErrorMode(Message, Message, Message, Message)
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event DocumentInserter.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "FILE_UPLOAD_COMPLETED")
  {
    IDArray uploadedFiles = UIBusinessLogic.UIBusinessLogicCommunication.GetUploadedFilesArray()
    DocumentoInserter di = DocumentoInserter.document
    if (di)
    {
      di.Filepath = uploadedFiles.getValue(0)
      di.computeAddtionalProperties()
    }
     
    // set again fileupload mode to multiple files
    // if singleFile Mode was selected and just after it you try to upload multiple files it works for single file only
    // so we always keep upload mode = multiple files and we set upload mode to single owhen this "add new from file" is selected
    UIBusinessLogic.UIBusinessLogicCommunication.SetFileUploadMode(multpleFiles)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MultipleDocumentInserter.showForm(
  IDForm callerForm                              // Write a comment for this parameter or press backspace to delete this comment
  IDCollection docInserters of DocumentoInserter // Write a comment for this parameter or press backspace to delete this comment
  int:openAs openAs                              // 
)
{
  if (docInserters)
  {
    this.CallerForm = callerForm
    DocumentoInserter.setCollection(docInserters, true)
    this.show(openAs)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MultipleDocumentInserter.ButtonOK()
{
//  DocumentoInserter.updateData()
  IDCollection coll of DocumentoInserter = DocumentoInserter.collection
  Cartella docCartella = null
  boolean anyDocumentIsInvalid = false
   
  boolean saveme = false
  for each DocumentoInserter di in coll
  {
    docCartella = di.Cartella
    boolean isValid = di.validate(...)
    if (!(isValid))
    {
      anyDocumentIsInvalid = true
    }
  }
  if (anyDocumentIsInvalid)
  {
    DocumentoInserter.showDocErrors(...)
  }
  else 
  {
    this.InsertDocuments()
    this.CallerForm.sendMessage("DocumentAdded", docCartella, ...)
    this.close(false)
  }
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MultipleDocumentInserter.InsertDocuments()
{
  IDCollection coll of DocumentoInserter = DocumentoInserter.collection
  for each DocumentoInserter di in coll
  {
    Documento d = di.generateDocument(true)
    d.saveToDB(...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MultipleDocumentInserter.Delete()
{
  DocumentoInserter di = DocumentoInserter.document
  if (di)
  {
    di.deleted = true
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event MultipleDocumentInserter.Load()
{
  DocumentoInserter.setErrorMode(Message, Message, Message, Message)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocumentiSearch.showform(
  IDForm callerForm                                            // Write a comment for this parameter or press backspace to delete this comment
  optional string:documentSearchTypes searchType = "SearchAll" // 
)
{
  this.CallerForm = callerForm
  this.SearchType = searchType
  this.loadPanel()
  this.show(Modal)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocumentiSearch.loadPanel()
{
  string searchString = ""
  if (Search.SearchString != null)
  {
    searchString = Search.SearchString
  }
  IDCollection documents of Documento = Documento.searchDocumentsBasedOnPrivilege(QappCore.Loggeduser, SearchAll, searchString)
  Documenti.setCollection(documents, true)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DocumentiSearch.Load()
{
  Search.SearchString = ""
   
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event DocumentiSearch.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm)
  {
    Documento document = Documenti.document
    if (document)
    {
      if (this.SearchType == Template)
      {
         string errorMessage = ""
         if (!(document.extensionSupportedByNuovoDaTemplate(errorMessage)))
         {
           Cancel = true
           UIBusinessLogic.messageBox(errorMessage)
           return 
         }
      }
      this.CallerForm.sendMessage("DocumentSelected", document, ...)
    }
  }
}


// ──────────────────────────────────

// **************************************************************
// Event raised by the panel at the end of the data saving cycle.
// **************************************************************
event DocumentiSearch.Search.AfterCommit(
  int RowsUpdated  // Number of rows that have been updated or inserted successfully.
  int RowsInErrors // Number of rows that were not updated or inserted due to database errors.
)
{
  this.loadPanel()
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CommonConfirmationFrom.ButtonOk()
{
  this.Callerform.sendMessage(this.Message, this.Doc, ...)
  this.close(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CommonConfirmationFrom.ShowForm(
  string messageTitle                  // 
  string buttonOkText                  // 
  string buttonAnnullaText             // 
  IDForm callerForm                    // 
  string messageToCallerForm           // 
  string askMessage                    // 
  optional IDDocument doc              // 
  optional string:icons iconTitle = "" // 
  optional string:icons buttonOkIcon = "" // 
)
{
  ConfirmationPanel.ButtonOK.text = buttonOkIcon + buttonOkText
  ConfirmationPanel.ButtonANNULLA.text = buttonAnnullaText
  ConfirmationPanel.LabelConferma.text = iconTitle + messageTitle
  ConfirmationPanel.LabelQuestion.text = askMessage
   
  this.Callerform = callerForm
  this.Message = messageToCallerForm
  this.Doc = doc
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DeleteConfirmationFrom.ButtonAnnulla()
{
  this.close(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DeleteConfirmationFrom.ButtonOk()
{
  if (ConfirmationPanel.textConfirmation.text != "ELIMINA")
  {
    UIBusinessLogic.messageBox("La parola digitata non è corretta")
    return 
  }
   
  this.Callerform.sendMessage(this.Message, this.Doc, ...)
  this.close(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DeleteConfirmationFrom.ShowForm(
  IDForm callerForm          // 
  string messageToCallerForm // 
  optional IDDocument doc    // 
)
{
  ConfirmationPanel.ButtonOK.text = "OK"
  ConfirmationPanel.ButtonANNULLA.text = "Annulla"
   
  this.Callerform = callerForm
  this.Message = messageToCallerForm
  this.Doc = doc
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void IconPicker.FaIcon()
{
  selectionpanel.chosenIcon = IconPicekrBook.FaIcon
  this.close(true)
}


// ──────────────────────────────────

// ***************************************************************
// Event fired by a section when it is being prepared for printing
// ***************************************************************
event IconPicker.IconPicekrBook.NewReport.Detail.BeforeFormatting()
{
   
//  // here we could change at runtime the number of columns (based may be on the total number of icons, it is commented since it is a placeholder
//  IconPicekrBook.NewReport.Detail.columnNumber = 12
   
  if (IconPicekrBook.NewReport.freezed)
  {
    IconPicekrBook.NewReport.freezed = false
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void IconPicker.showForm()
{
  this.show(Modal)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void OneWayUpgraderProgressForm.showForm()
{
  this.showMessage(..., "Attendere che tutte le righe vengano processate, quindi premere esci ed effettuare nuovamente l'accesso")
  this.refreshPanelCollection()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void OneWayUpgraderProgressForm.logout()
{
  Tools.performExit(...)
}


// ──────────────────────────────────



// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event OneWayUpgraderProgressForm.Load()
{
  OneWayUpgraderProgress.DONECOUNT.setEnabled(false)
  OneWayUpgraderProgress.TOTALCOUNT.setEnabled(false)
  OneWayUpgraderProgress.STATUSCODE.setEnabled(false)
  OneWayUpgraderProgress.TABLEFIELDINFO.setEnabled(false)
  OneWayUpgraderProgress.CONVERSIONINFO.setEnabled(false)
  OneWayUpgraderProgress.CREATEDON.setEnabled(false)
  OneWayUpgraderProgress.COMPLETEDON.setEnabled(false)
   
  UiRefreshTimer.enabled = true
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event OneWayUpgraderProgressForm.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
   
  // avoid form is closed by double click on a panel row
  Cancel = true
  UIBusinessLogic.DTTLogMessage("User tried to close the form, canceling it", ..., DTTWarning)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void OneWayUpgraderProgressForm.UiRefreshTimer()
{
  UiRefreshTimer.enabled = false
  this.refreshPanelCollection()
  UiRefreshTimer.enabled = true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CommonMainModuleTabbedView.attachMultipleSubforms(
  IDArray idFormArray               // Subforms to display, in slot order (slot 0 = idFormArray[0], etc.)
  MainModule mainModule             // 
  optional IDForm idFormToBeFocused // 
  optional boolean clear = 0        //  legacy parameter, ignored: with slot-based attach we always reset visibility
)
{
  this.MainModule = mainModule
  this.CurrentlyFocusedTabForm = idFormToBeFocused
  this.SubformsArray = idFormArray
   
  if (idFormToBeFocused)
    UIBusinessLogic.DTTLogMessage("RELOAD - form name to be focused: " + idFormToBeFocused.className(), 465, DTTWarning)
   
  // Reset: hide all 20 design-time slots. Subforms previously assigned via setLabelSubForm
  // are not destroyed — they remain assigned to their slot but invisible until reassigned below.
  this.hideAllTabs()
  this.AttachedIdforms.clear()
  this.clearTabSlotLoadedFlags()
   
  int indexOfFormToBeFocused = 0
  for (int i = 0; i < idFormArray.length(); i = i + 1)
  {
    IDForm currentIdForm = (IDForm)idFormArray.getObject(i)
     
    if (currentIdForm == null)
    {
      UIBusinessLogic.DTTLogMessage("currentIdForm is null at index " + toString(i) + ", should not happen", ..., DTTError)
      continue 
    }
     
    UIBusinessLogic.DTTLogMessage("Form type: " + currentIdForm.className(), ..., DTTInfo)
     
    // fallback to focus the first form attached
    if (idFormToBeFocused == null)
      idFormToBeFocused = currentIdForm
     
    boolean focusIdFormAfterAttaching = (currentIdForm.className() == idFormToBeFocused.className())
     
    this.setTabSubForm(i, currentIdForm, currentIdForm.caption)
    this.AttachedIdforms.addObject(currentIdForm)
     
    if (focusIdFormAfterAttaching)
    {
      indexOfFormToBeFocused = i
      UIBusinessLogic.DTTLogMessage(formatMessage("RELOAD - Tab focused => slot: |1  Name: |2", i, currentIdForm.className(), ...), 465, DTTWarning)
    }
    else 
    {
      UIBusinessLogic.DTTLogMessage(formatMessage("RELOAD - Tab assigned => slot: |1  Name: |2", i, currentIdForm.className(), ...), 465, DTTWarning)
    }
     
  }
  UIBusinessLogic.DTTLogMessage("RELOAD - selectTabAt: " + toString(indexOfFormToBeFocused), 465, DTTWarning)
  this.setTag("indexOfFormToBeFocused", indexOfFormToBeFocused)
  this.selectTabAt(indexOfFormToBeFocused)
   
  // ChangePage does not fire for programmatic selectPage, so trigger LOAD
  // manually for the focused slot. Subsequent user-driven tab changes will
  // be handled by the ChangePage event normally.
  if (indexOfFormToBeFocused >= 0 and indexOfFormToBeFocused < this.AttachedIdforms.length())
  {
    IDForm focusedIdf = (IDForm)this.AttachedIdforms.getObject(indexOfFormToBeFocused)
    this.CurrentlyFocusedTabForm = focusedIdf
    if (!(isTabSlotLoaded(indexOfFormToBeFocused)))
    {
      UIBusinessLogic.DTTLogMessage("attachMultipleSubforms: triggering initial LOAD for slot " + toString(indexOfFormToBeFocused) + " --> " + focusedIdf.className(), 465, DTTWarning)
      this.loadSubform(focusedIdf)
      this.markTabSlotLoaded(indexOfFormToBeFocused)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CommonMainModuleTabbedView.deleteAllSubforms()
{
  // Slot-based: hide the 20 design-time slots. Subforms hosted via setLabelSubForm
  // remain assigned but invisible; a subsequent attachMultipleSubforms will overwrite them.
  // No form.close() needed: design-time slots are reused, not destroyed.
   
  this.hideAllTabs()
  this.AttachedIdforms.clear()
}


// ──────────────────────────────────

// *****************************************************************************
// Rebuilds the visible tab strip in displayOrder using the currently filtered
// tab configuration. For each desired SubformType:
// - If an instance already exists in AttachedIdforms (matched by getTag
//   "subformType"), it is reused (state preserved).
// - Otherwise SubformFactory creates a new instance.
// Subforms whose SubformType is no longer in the filtered config are dropped
// from AttachedIdforms (their TabSlot binding stays in a hidden slot until the
// form is closed).
// 
// After the structural rebuild, all per-slot loaded flags are reset and LOAD is
// re-sent to the currently focused tab so the user sees fresh data immediately.
// Other tabs stay lazy until clicked.
// *****************************************************************************
public void CommonMainModuleTabbedView.applyTabConfigDelta(
  MainModuleUILogic uiLogic // Write a comment for this parameter or press backspace to delete this comment
)
{
  if (uiLogic == null)
  {
    return 
  }
   
  IDArray desiredTabDefs = uiLogic.getFilteredTabConfiguration()
   
  // Snapshot currently-parked subforms by SubformType so we can reuse instances
  // and preserve state (loaded subforms keep their data, panels keep selection,
  // etc.).
  IDMap existingType = new()
  for (int i = 0; i < this.AttachedIdforms.length(); i = i + 1)
  {
    IDForm idf = (IDForm)this.AttachedIdforms.getObject(i)
    if (idf != null)
    {
      string type = idf.getTag("subformType")
      existingType.setObject(type, idf)
    }
  }
   
  // Reset state: hide all 20 slots and clear bookkeeping arrays. We will rebuild
  // them in displayOrder below.
  this.hideAllTabs()
  this.AttachedIdforms.clear()
  this.SubformsArray.clear()
   
  // Reassign slots 0..N-1 in displayOrder. Reuse the existing IDForm instance for
  // each SubformType where available; create a new one only for first-time tabs.
  // Subforms dropped from the filtered config are not re-added — their IDForms
  // become unreferenced and will be Garbage Collected
  for (int j = 0; j < desiredTabDefs.length(); j = j + 1)
  {
    TabDefinition td = (TabDefinition)desiredTabDefs.getObject(j)
     
    IDForm subform = null
    boolean isNew = true
    if (existingType.containsKey(td.SubformType))
    {
      subform = (IDForm)existingType.getObject(td.SubformType)
      isNew = false
    }
     
    if (isNew)
    {
      subform = SubformFactory.createSubform(td)
      if (subform == null)
      {
         UIBusinessLogic.DTTLogMessage("applyTabConfigDelta: factory returned null for " + td.SubformType, 465, DTTError)
         continue 
      }
    }
     
    int slot = j
    if (slot >= 20)
    {
      UIBusinessLogic.DTTLogMessage("applyTabConfigDelta: filtered config exceeds 20 slots, dropping " + td.SubformType, 465, DTTError)
      break 
    }
     
    this.setTabSubForm(slot, subform, subform.caption)
    this.AttachedIdforms.addObject(subform)
    this.SubformsArray.addObject(subform)
     
    string statusTag = " (reused)"
    if (isNew)
    {
      statusTag = " (new)"
    }
    UIBusinessLogic.DTTLogMessage("applyTabConfigDelta: slot " + toString(slot) + " <- " + td.SubformType + statusTag, 465, DTTWarning)
     
    // Eager LOAD for newly-created subforms marked LoadInitially=true.
    // Reused subforms keep their existing loaded state (managed via tabSlotLoaded
    // tags below).
    if (isNew and td.LoadInitially)
    {
      this.loadSubform(subform)
    }
  }
   
  // Refresh: send LOAD to ALL parked subforms so each one re-binds to the
  // freshly reloaded MainModule. Without this, widgets that don't observe
  // MainModule changes (e.g. HTML editor) keep showing stale data after
  // performRefresh. loadSubform internally marks each slot as loaded.
  this.clearTabSlotLoadedFlags()
   
  for (int k = 0; k < this.AttachedIdforms.length(); k = k + 1)
  {
    IDForm idf = (IDForm)this.AttachedIdforms.getObject(k)
    if (idf != null)
    {
      this.loadSubform(idf)
    }
     
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CommonMainModuleTabbedView.handleTabsForWorkflowType(
  IDForm subform                       // 
  string:eventiBehaviours workflowType // 
)
{
  if (subform == null)
  {
    return 
  }
   
  // Workflow and Disposizioni are mutually exclusive: toggling the workflow type
  // swaps one for the other in-place at the same slot. Determine the class name
  // of the subform being REPLACED (the one currently occupying the slot).
  string oldClassName = ""
  if (workflowType == Workflow)
  {
    oldClassName = ModelliDisposizioniSubform.className()
  }
  else if (workflowType == Normal)
  {
    oldClassName = WorkflowDiagramSubform.className()
  }
  else 
  {
    UIBusinessLogic.DTTLogMessage("handleTabsForWorkflowType: unknown workflowType " + workflowType, ..., DTTError)
    return 
  }
   
  int slot = findSlotByClassName(oldClassName)
  if (slot >= 0)
  {
     
    // Swap-in-place: same slot, new subform. AttachedIdforms must stay in sync
    // so ChangePage and loadSubform find the correct IDForm at this slot.
    this.setTabSubForm(slot, subform, subform.caption)
    this.AttachedIdforms.setObject(slot, subform)
    this.SubformsArray.setObject(slot, subform)
     
    // The new subform hasn't received LOAD yet — reset the per-slot flag so
    // ChangePage will trigger LOAD on the next user activation of this slot.
    this.setTag("tabSlotLoaded_" + toString(slot), "0")
    UIBusinessLogic.DTTLogMessage("handleTabsForWorkflowType: swapped slot " + toString(slot) + " <-- " + subform.className(), 465, DTTWarning)
    return 
  }
   
  // Old subform not parked (unexpected state). Fall back to show-or-append.
  int existingSlot = findSlotByClassName(subform.className())
  if (existingSlot >= 0)
  {
    this.showTab(existingSlot)
    return 
  }
   
  int newSlot = this.AttachedIdforms.length()
  if (newSlot >= 20)
  {
    UIBusinessLogic.DTTLogMessage("handleTabsForWorkflowType: no free slot available", ..., DTTError)
    return 
  }
  this.setTabSubForm(newSlot, subform, subform.caption)
  this.AttachedIdforms.addObject(subform)
  this.SubformsArray.addObject(subform)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CommonMainModuleTabbedView.sendLockMessage(
  boolean shouldChangeMessageAlsoToParentForm // 
)
{
  for (int i = 0; i < this.SubformsArray.length(); i = i + 1)
  {
    IDForm idf = (IDForm)this.SubformsArray.getObject(i)
    idf.sendMessage(LOCK_PANELS, ...)
  }
   
  if (shouldChangeMessageAlsoToParentForm)
  {
    this.MainModuleDetailForm.sendMessage("EVENTO_HAS_BEEN_CLOSED", ...)
  }
}


// ──────────────────────────────────

// *************************************************************************
// Sends LOAD to a subform and marks its slot as loaded so ChangePage will
// not re-send LOAD on the first user-driven activation. Called by the eager
// preload path (loadSubformsThatMustBeInitiallyLoaded) and by the lazy path
// (ChangePage event for slots not yet loaded).
// *************************************************************************
public void CommonMainModuleTabbedView.loadSubform(
  IDForm subForm // Write a comment for this parameter or press backspace to delete this comment
)
{
  subForm.sendMessage("LOAD", this.MainModule, ...)
   
  // Mark the corresponding slot as loaded.
  for (int i = 0; i < this.AttachedIdforms.length(); i = i + 1)
  {
    IDForm cur = (IDForm)this.AttachedIdforms.getObject(i)
    if (cur.className() == subForm.className())
    {
      this.markTabSlotLoaded(i)
      return 
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm CommonMainModuleTabbedView.GetCurrentlyFocusedForm()
{
  if (this.CurrentlyFocusedTabForm != null)
    UIBusinessLogic.DTTLogMessage("RELOAD - GetFocusedForm: " + this.CurrentlyFocusedTabForm.className(), 465, DTTWarning)
  else 
    UIBusinessLogic.DTTLogMessage("RELOAD - GetFocusedForm: <not set>", 465, DTTWarning)
   
  return this.CurrentlyFocusedTabForm
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm CommonMainModuleTabbedView.getMainFormReference()
{
  return this.MainModuleDetailForm
}


// ──────────────────────────────────

// ***************************************************************************
//   Replaces the subform parked at the given slot with a freshly created
//   instance of the same SubformType, then loads it. Tabs whose layout is
//   built at runtime (custom-data group headers) need this: re-binding the
//   existing instance is a no-op render, so the runtime groups never appear.
//   A brand-new instance has never been rendered to the client, so its bind
//   plus LOAD happen as one fresh render in the same round-trip and the group
//   headers materialize. Also the primitive to call on refresh to truly
//   rebuild a custom-data tab instead of reusing its stale instance.
// ***************************************************************************
public void CommonMainModuleTabbedView.recreateAndLoadSubform(
  int slotIdx       // 0-based slot index (0..19) to rebuild
  IDForm currentIdf // subform currently parked at the slot, read to get its SubformType
)
{
  string:moduleSubformTypes subformType = currentIdf.getTag("subformType")
  TabDefinition td = new()
  td.SubformType = subformType
  IDForm freshSubform = SubformFactory.createSubform(td)
  if (freshSubform == null)
  {
     
    // factory failed: fall back to loading the existing instance so the tab still works
    UIBusinessLogic.DTTLogMessage("recreateAndLoadSubform: factory null for " + subformType + ", fallback to plain load", 465, DTTError)
    this.loadSubform(currentIdf)
    return 
  }
  this.setTabSubForm(slotIdx, freshSubform, freshSubform.caption)
  this.AttachedIdforms.setObject(slotIdx, freshSubform)
  this.SubformsArray.setObject(slotIdx, freshSubform)
  this.CurrentlyFocusedTabForm = freshSubform
  this.setObjectTag("idFormToBeFocused", freshSubform)
  this.loadSubform(freshSubform)
}


// ──────────────────────────────────

// ******************************************************************
// Assigns a subform to the tab at the given slot index and makes the
// // tab visible. Tab caption becomes the provided string.
// // 
// // index   : 0-based slot index (0..19)
// // subform : IDForm instance to display inside the tab
// // caption : human-readable label shown on the tab
// ******************************************************************
public void CommonMainModuleTabbedView.setTabSubForm(
  int index      // 0-based slot index (0..19)
  IDForm subform // instance to display inside the tab
  string caption // human-readable label shown on the tab
)
{
  switch (index)
  {
    case 0:
      TabPanel1.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel1.me(), caption)
      TabPanel1.visible = true
    break
    case 1:
      TabPanel2.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel2.me(), caption)
      TabPanel2.visible = true
    break
    case 2:
      TabPanel3.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel3.me(), caption)
      TabPanel3.visible = true
    break
    case 3:
      TabPanel4.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel4.me(), caption)
      TabPanel4.visible = true
    break
    case 4:
      TabPanel5.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel5.me(), caption)
      TabPanel5.visible = true
    break
    case 5:
      TabPanel6.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel6.me(), caption)
      TabPanel6.visible = true
    break
    case 6:
      TabPanel7.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel7.me(), caption)
      TabPanel7.visible = true
    break
    case 7:
      TabPanel8.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel8.me(), caption)
      TabPanel8.visible = true
    break
    case 8:
      TabPanel9.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel9.me(), caption)
      TabPanel9.visible = true
    break
    case 9:
      TabPanel10.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel10.me(), caption)
      TabPanel10.visible = true
    break
    case 10:
      TabPanel11.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel11.me(), caption)
      TabPanel11.visible = true
    break
    case 11:
      TabPanel12.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel12.me(), caption)
      TabPanel12.visible = true
    break
    case 12:
      TabPanel13.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel13.me(), caption)
      TabPanel13.visible = true
    break
    case 13:
      TabPanel14.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel14.me(), caption)
      TabPanel14.visible = true
    break
    case 14:
      TabPanel15.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel15.me(), caption)
      TabPanel15.visible = true
    break
    case 15:
      TabPanel16.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel16.me(), caption)
      TabPanel16.visible = true
    break
    case 16:
      TabPanel17.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel17.me(), caption)
      TabPanel17.visible = true
    break
    case 17:
      TabPanel18.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel18.me(), caption)
      TabPanel18.visible = true
    break
    case 18:
      TabPanel19.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel19.me(), caption)
      TabPanel19.visible = true
    break
    case 19:
      TabPanel20.TabSlot.setLabelSubForm(subform, ...)
      CommonTabbedView.setCaption(TabPanel20.me(), caption)
      TabPanel20.visible = true
    break
    default:
      UIBusinessLogic.DTTLogMessage(formatMessage("setTabSubForm: index |1 out of range (0..19)", index, ...), ..., DTTError)
    break
  }
}


// ──────────────────────────────────

// *************************************************************
// Hides the tab at the given slot index. The underlying subform
// (if any) keeps its setLabelSubForm assignment — we only flip
// visibility so a later showTab restores it instantly.
// *************************************************************
public void CommonMainModuleTabbedView.hideTab(
  int index // 0-based slot index (0..19)
)
{
  switch (index)
  {
    case 0:
      TabPanel1.visible = false
    break
    case 1:
      TabPanel2.visible = false
    break
    case 2:
      TabPanel3.visible = false
    break
    case 3:
      TabPanel4.visible = false
    break
    case 4:
      TabPanel5.visible = false
    break
    case 5:
      TabPanel6.visible = false
    break
    case 6:
      TabPanel7.visible = false
    break
    case 7:
      TabPanel8.visible = false
    break
    case 8:
      TabPanel9.visible = false
    break
    case 9:
      TabPanel10.visible = false
    break
    case 10:
      TabPanel11.visible = false
    break
    case 11:
      TabPanel12.visible = false
    break
    case 12:
      TabPanel13.visible = false
    break
    case 13:
      TabPanel14.visible = false
    break
    case 14:
      TabPanel15.visible = false
    break
    case 15:
      TabPanel16.visible = false
    break
    case 16:
      TabPanel17.visible = false
    break
    case 17:
      TabPanel18.visible = false
    break
    case 18:
      TabPanel19.visible = false
    break
    case 19:
      TabPanel20.visible = false
    break
    default:
      UIBusinessLogic.DTTLogMessage(formatMessage("hideTab: index |1 out of range (0..19)", index, ...), ..., DTTError)
    break
  }
}


// ──────────────────────────────────

// *****************************************************************
// Shows the tab at the given slot index. Use after setTabSubform if
// a tab was previously hidden, or to reveal a tab whose subform was
// already assigned in a previous call.
// *****************************************************************
public void CommonMainModuleTabbedView.showTab(
  int index // 0-based slot index (0..19)
)
{
  switch (index)
  {
    case 0:
      TabPanel1.visible = true
    break
    case 1:
      TabPanel2.visible = true
    break
    case 2:
      TabPanel3.visible = true
    break
    case 3:
      TabPanel4.visible = true
    break
    case 4:
      TabPanel5.visible = true
    break
    case 5:
      TabPanel6.visible = true
    break
    case 6:
      TabPanel7.visible = true
    break
    case 7:
      TabPanel8.visible = true
    break
    case 8:
      TabPanel9.visible = true
    break
    case 9:
      TabPanel10.visible = true
    break
    case 10:
      TabPanel11.visible = true
    break
    case 11:
      TabPanel12.visible = true
    break
    case 12:
      TabPanel13.visible = true
    break
    case 13:
      TabPanel14.visible = true
    break
    case 14:
      TabPanel15.visible = true
    break
    case 15:
      TabPanel16.visible = true
    break
    case 16:
      TabPanel17.visible = true
    break
    case 17:
      TabPanel18.visible = true
    break
    case 18:
      TabPanel19.visible = true
    break
    case 19:
      TabPanel20.visible = true
    break
    default:
      UIBusinessLogic.DTTLogMessage(formatMessage("showTab: index |1 out of range (0..19)", index, ...), ..., DTTError)
    break
  }
}


// ──────────────────────────────────

// ****************************************************************************
// Selects (focuses) the tab at the given slot index. Uses the design-time
// panel reference so it works regardless of how many earlier slots are hidden.
// ****************************************************************************
public void CommonMainModuleTabbedView.selectTabAt(
  int index // 0-based slot index (0..19)
)
{
  switch (index)
  {
    case 0:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel1.me()))
    break
    case 1:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel2.me()))
    break
    case 2:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel3.me()))
    break
    case 3:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel4.me()))
    break
    case 4:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel5.me()))
    break
    case 5:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel6.me()))
    break
    case 6:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel7.me()))
    break
    case 7:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel8.me()))
    break
    case 8:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel9.me()))
    break
    case 9:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel10.me()))
    break
    case 10:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel11.me()))
    break
    case 11:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel12.me()))
    break
    case 12:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel13.me()))
    break
    case 13:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel14.me()))
    break
    case 14:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel15.me()))
    break
    case 15:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel16.me()))
    break
    case 16:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel17.me()))
    break
    case 17:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel18.me()))
    break
    case 18:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel19.me()))
    break
    case 19:
      CommonTabbedView.selectPage(CommonTabbedView.getPageIndex(TabPanel20.me()))
    break
    default:
      UIBusinessLogic.DTTLogMessage(formatMessage("selectTabAt: index |1 out of range (0..19)", index, ...), ..., DTTError)
    break
  }
}


// ──────────────────────────────────

// *****************************************************************************
// Reverse lookup: given a TabbedView page index, returns the slot index (0..19)
// of the design-time TabPanel hosting it, or -1 if the page is not one of our
// 20 design-time slots (e.g. a stray runtime-added page).
// *****************************************************************************
public int CommonMainModuleTabbedView.getSlotIndexForPageIndex(
  int pageIndex // page index as returned by CommonTabbedView.selectedPage(
)
{
  int slotIndex = 0
  if (TabPanel1.me() == pageIndex)
  {
    slotIndex = 0
  }
  else if (TabPanel2.me() == pageIndex)
  {
    slotIndex = 1
  }
  else if (TabPanel3.me() == pageIndex)
  {
    slotIndex = 2
  }
  else if (TabPanel4.me() == pageIndex)
  {
    slotIndex = 3
  }
  else if (TabPanel5.me() == pageIndex)
  {
    slotIndex = 4
  }
  else if (TabPanel6.me() == pageIndex)
  {
    slotIndex = 5
  }
  else if (TabPanel7.me() == pageIndex)
  {
    slotIndex = 6
  }
  else if (TabPanel8.me() == pageIndex)
  {
    slotIndex = 7
  }
  else if (TabPanel9.me() == pageIndex)
  {
    slotIndex = 8
  }
  else if (TabPanel10.me() == pageIndex)
  {
    slotIndex = 9
  }
  else if (TabPanel11.me() == pageIndex)
  {
    slotIndex = 10
  }
  else if (TabPanel12.me() == pageIndex)
  {
    slotIndex = 11
  }
  else if (TabPanel13.me() == pageIndex)
  {
    slotIndex = 12
  }
  else if (TabPanel14.me() == pageIndex)
  {
    slotIndex = 13
  }
  else if (TabPanel15.me() == pageIndex)
  {
    slotIndex = 14
  }
  else if (TabPanel16.me() == pageIndex)
  {
    slotIndex = 15
  }
  else if (TabPanel17.me() == pageIndex)
  {
    slotIndex = 16
  }
  else if (TabPanel18.me() == pageIndex)
  {
    slotIndex = 17
  }
  else if (TabPanel19.me() == pageIndex)
  {
    slotIndex = 18
  }
  else if (TabPanel20.me() == pageIndex)
  {
    slotIndex = 19
  }
  else 
  {
    UIBusinessLogic.DTTLogMessage(formatMessage("Invalid pageIndex passed: |1", slotIndex, ...), ..., DTTError)
    slotIndex = -1
  }
   
  return slotIndex
}


// ──────────────────────────────────

// *****************************************************
// Hides all 20 design-time tab slots in one go.
// Used to reset visibility before reassigning subforms.
// *****************************************************
public void CommonMainModuleTabbedView.hideAllTabs()
{
  for (int i = 0; i < 20; i = i + 1)
  {
    this.hideTab(i)
  }
}


// ──────────────────────────────────

// ********************************************************************
// Returns the slot index (0..19) where a subform of the given class
// is currently parked, or -1 if no such subform is in AttachedIdforms.
// ********************************************************************
private int CommonMainModuleTabbedView.findSlotByClassName(
  string className // class name to look up (e.g. WorkflowDiagramSubform.className())
)
{
  for (int i = 0; i < this.AttachedIdforms.length(); i = i + 1)
  {
    IDForm cur = (IDForm)this.AttachedIdforms.getObject(i)
    if (cur != null and cur.className() == className)
    {
      return i
    }
  }
  return -1
}


// ──────────────────────────────────

// ********************************************************
// Marks the given slot as already-loaded. Once marked, the
// ChangePage event won't re-send LOAD to its subform.
// ********************************************************
private void CommonMainModuleTabbedView.markTabSlotLoaded(
  int slotIdx // 0-based slot index (0..19)
)
{
  this.setTag("tabSlotLoaded_" + toString(slotIdx), "1")
}


// ──────────────────────────────────

// *********************************************************
// Returns true if the given slot has already received LOAD.
// *********************************************************
private boolean CommonMainModuleTabbedView.isTabSlotLoaded(
  int slotIdx // 0-based slot index (0..19)
)
{
  return (this.getTag("tabSlotLoaded_" + toString(slotIdx)) == "1")
}


// ──────────────────────────────────

// ***************************************************************************
// Resets all per-slot load flags. Called by attachMultipleSubforms so a fresh
// module attach starts with no slot considered loaded — the first ChangePage
// on each slot will (re)trigger LOAD.
// ***************************************************************************
private void CommonMainModuleTabbedView.clearTabSlotLoadedFlags()
{
  for (int i = 0; i < 20; i = i + 1)
  {
    this.setTag("tabSlotLoaded_" + toString(i), "0")
  }
}


// ──────────────────────────────────

// *********************************************************************
// The Tabbed View object raises this event when the active page changes
// *********************************************************************
event CommonMainModuleTabbedView.CommonTabbedView.ChangePage(
  int PreviousPage     // An integer representing the index of the page previously selected in the Tabbed View. Use the Me function of the panel or visual object contained in the Tabbed View to make the comparison.
  inout boolean Cancel // If set to True, cancels the page change.
)
{
  this.CurrentlyFocusedTabForm = null
   
  int currentPageIndex = CommonTabbedView.selectedPage()
  int currentSlotIdx = getSlotIndexForPageIndex(currentPageIndex)
   
  if (currentSlotIdx < 0)
  {
    // selected page does not correspond to any design-time slot (e.g. stray runtime page)
    UIBusinessLogic.DTTLogMessage("ChangePage: pageIndex " + toString(currentPageIndex) + " has no matching slot, skipping", 465, DTTWarning)
    return 
  }
   
  if (currentSlotIdx >= this.AttachedIdforms.length())
  {
    UIBusinessLogic.DTTLogMessage("ChangePage: slot " + toString(currentSlotIdx) + " has no attached IDForm (AttachedIdforms.length=" + toString(this.AttachedIdforms.length()) + ")", 465, DTTWarning)
    return 
  }
   
  IDForm idf = (IDForm)this.AttachedIdforms.getObject(currentSlotIdx)
  this.CurrentlyFocusedTabForm = idf
  this.setObjectTag("idFormToBeFocused", idf)
  UIBusinessLogic.DTTLogMessage("ChangePage: focused slot " + toString(currentSlotIdx) + " --> " + idf.className(), 465, DTTWarning)
   
  // Lazy LOAD: send LOAD only the first time this slot becomes focused.
  if (!(isTabSlotLoaded(currentSlotIdx)))
  {
    UIBusinessLogic.DTTLogMessage("ChangePage: first activation of slot " + toString(currentSlotIdx) + " , sending LOAD", 465, DTTWarning)
     
    // custom-data tabs build their group layout at runtime: they need a fresh subform instance to render it; other tabs just load
    if (idf.className() == CustomDataSubform.className())
      this.recreateAndLoadSubform(currentSlotIdx, idf)
    else 
      this.loadSubform(idf)
    this.markTabSlotLoaded(currentSlotIdx)
  }
  else 
  {
    UIBusinessLogic.DTTLogMessage("ChangePage: slot " + toString(currentSlotIdx) + " already loaded, skipping LOAD", 465, DTTWarning)
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event CommonMainModuleTabbedView.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "DELETE_PAGES":
      this.deleteAllSubforms()
    break
    case "ATTACH_MULTIPLE_SUBFORMS":
      IDArray subFormArray = (IDArray)Doc.getObjectTag("idFormArray")
      MainModule mainModule = (MainModule)Doc.getObjectTag("mainModule")
      IDForm idFormToBeFocused = (IDForm)Doc.getObjectTag("idFormToBeFocused")
       
      this.attachMultipleSubforms(subFormArray, mainModule, idFormToBeFocused, true)
    break
    case "LOAD":
      IDForm subformToBeLoaded = (IDForm)Doc.getObjectTag("subform")
      this.loadSubform(subformToBeLoaded)
    break
    case "GET_FOCUSED_ID_FORM":
      Doc.setObjectTag("focusedIdForm", this.CurrentlyFocusedTabForm)
    break
    case "SAVE":
      this.MainModuleDetailForm.sendMessage("SAVE", ...)
    break
    case "EVENTO_HAS_BEEN_CLOSED":
    case "MAIN_MODULE_IS_CLOSED":
      this.sendLockMessage(Message == "EVENTO_HAS_BEEN_CLOSED")
    break
    case UNLOCK_PANELS:
      for (int i = 0; i < this.SubformsArray.length(); i = i + 1)
      {
         IDForm idf = (IDForm)this.SubformsArray.getObject(i)
         idf.sendMessage(UNLOCK_PANELS, ...)
      }
    break
    case "WORKFLOW_TYPE_CHANGED":
      IDForm subform = (IDForm)Doc.getObjectTag("subform")
      this.handleTabsForWorkflowType(subform, Par1)
    break
    case "refreshDiagram":
      if (Evento.isMyInstance(this.MainModule))
      {
         for (int i = 0; i < this.AttachedIdforms.length(); i = i + 1)
         {
           IDForm currentIdForm = (IDForm)this.AttachedIdforms.getObject(i)
           if (currentIdForm.className() == WorkflowDiagramSubform.className())
           {
             // do not refresh or reload the diagram if it is not loaded already
             int tabSlotIndex = findSlotByClassName(WorkflowDiagramSubform.className())
             if (isTabSlotLoaded(tabSlotIndex))
             {
                Evento currentEvento = cast(this.MainModule)
                currentIdForm.sendMessage(reloadDiagram, currentEvento, ...)
             }
           }
         }
      }
    break
    case "OPEN_MODELLO_EVENTO":
      this.MainModuleDetailForm.sendMessage("OPEN_MODELLO_EVENTO", Doc, ...)
    break
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event PromemoriaSubform.Load()
{
  Promemoria.setCommandEnabled(Update, false)
  Promemoria.setCommandEnabled(Navigate, false)
  Promemoria.setCommandEnabled(Delete, false)
  Promemoria.setCommandEnabled(Refresh, false)
  Promemoria.setCommandEnabled(Search, false)
  Promemoria.setCommandEnabled(Cancel, false)
  Promemoria.collapsable = false
  Promemoria.listQBE = No
   
  Promemoriaquickview.visible = false
  Promemoriaquickview.collapsable = false
  Promemoriaquickview.collapsed = false
   
  Addpromemoria.clickEventType = Urgent
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event PromemoriaSubform.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  boolean errorsExist = !(Confirm)
  if (errorsExist)
  {
    Cancel = true
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event PromemoriaSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "LOAD":
      MainModule c = (MainModule)Doc
      this.MainModule = c
      this.handleVisibilityOfModuleSpecificFields()
       
      // in principle the framework will load the collection only the first time
      c.loadCollectionFromDB(c.Promemoria, ...)
      Promemoria.setCollection(c.Promemoria, true)
    break
    case LOCK_PANELS:
      Promemoria.locked = true
      Promemoriaquickview.locked = true
      deletePromemoria.visible = false
      promemoriapopupmenu.visible = false
      Addpromemoria.visible = false
    break
    case UNLOCK_PANELS:
      Promemoria.locked = false
      Promemoriaquickview.locked = false
      deletePromemoria.visible = true
      promemoriapopupmenu.visible = true
      Addpromemoria.visible = true
    break
  }
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event PromemoriaSubform.Promemoria.OnChangeRow()
{
  if (this.MainModule)
  {
    this.changeVisibilityOfButtons(!(this.MainModule.isLocked()))
  }
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event PromemoriaSubform.Promemoria.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  if (Row > -1)
  {
    this.openQuickView()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PromemoriaSubform.insert()
{
  IDCollection promemorias of Promemoria = Promemoria.collection
  int:kordapp kordApp = this.MainModule.getKordApp()
  int mainID = this.MainModule.getMainID()
  Promemoria p = Promemoria.create(kordApp, mainID, ...)
  promemorias.add(p)
   
  // focus on the new promemoria
  Promemoria.findDocument(p)
   
  Promemoriaquickview.visible = true
  Promemoriaquickview.setDocument(p, true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PromemoriaSubform.handleVisibilityOfModuleSpecificFields()
{
  int:kordapp specifickordApp = this.MainModule.getKordApp()
   
  boolean visibilityOfCliforSpecificFields = false
  boolean visibilityOfProgettiSpecificFields = false
   
  switch (specifickordApp)
  {
    case ClientiFornitori:
      visibilityOfCliforSpecificFields = true
    break
    case Progetti:
      visibilityOfProgettiSpecificFields = true
    break
  }
   
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PromemoriaSubform.Chiudipromemoria()
{
  Promemoria p = Promemoria.document
  if (p)
  {
    if (!(p.isClosed()))
      ClosePromemoriaModal.showForm(p)
    else 
    {
      UIBusinessLogic.messageBox("Non è possibile chiudere un promemoria chiuso")
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PromemoriaSubform.ReopenPromemoria()
{
  UITools.displayNotImplementedMessage()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PromemoriaSubform.deletePromemoria()
{
  if (!(this.MainModule.isLocked()))
  {
    Promemoria p = Promemoria.document
    p.deleted = true
     
    IDCollection coll of Promemoria = Promemoria.collection
    if (coll)
    {
      if (coll.count() <= 0)
      {
         Promemoriaquickview.visible = false
      }
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PromemoriaSubform.openQuickView()
{
  Promemoria p = Promemoria.document
   
  if (p)
  {
    Promemoriaquickview.setDocument(p, true)
    Promemoriaquickview.caption = "Dettaglio promemoria"
    Promemoriaquickview.visible = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PromemoriaSubform.closequickview()
{
  Promemoriaquickview.visible = false
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void PromemoriaSubform.changeVisibilityOfButtons(
  boolean forceNotVisible // 
)
{
  Promemoria p = Promemoria.document
  if (p and forceNotVisible)
  {
    boolean isPromemoraClosable = p.isClosable()
    Closepromemoria.visible = isPromemoraClosable
     
    boolean isPromemoriaClosed = p.isClosed()
    ReopenPromemoria.visible = isPromemoriaClosed
     
    deletePromemoria.visible = true
  }
  else 
  {
    // in case of invalid document simply hide all
    Closepromemoria.visible = false
    ReopenPromemoria.visible = false
    deletePromemoria.visible = false
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DocComunicazioniSubform.Load()
{
  // settings to be understood better...
  ModuleDocuments.canGroup = true
  ModuleDocuments.showGroups = true
  ModuleDocuments.canResizeColumn = true
  ModuleDocuments.setCommandEnabled(Delete, false)
  ModuleDocuments.setCommandEnabled(Update, false)
  ModuleDocuments.setCommandEnabled(GroupPanel, false)
  ModuleDocuments.setCommandEnabled(Duplicate, false)
  ModuleDocuments.setCommandEnabled(Refresh, false)
  ModuleDocuments.setCommandEnabled(Navigate, false)
  ModuleDocuments.setCommandEnabled(Insert, false)
  ModuleDocuments.setCommandEnabled(Cancel, false)
  ModuleDocuments.collapsable = false
   
  Newdocument.clickEventType = Urgent
  newFromTemplate.clickEventType = Urgent
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event DocComunicazioniSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
   
  // waitingResult and notWaitingResult comes from OnlyOffice, they say if the OO Editor form is closed or not
  switch (Message)
  {
    case EditorResult:
      string filepath = Par1
      ModuleDocument md = (ModuleDocument)Doc
      boolean documentIsSupportedByOO = OnlyOfficeTools.extensionIsSupportedByEditor(md.ESTENSIONEFILE)
      if (md and documentIsSupportedByOO)
      {
         md.CHECKEDOUTFILE = filepath
         md.setTag("wait_for_result", false)
         this.applyVisibilitiesOnButtonsToolbar()
         WaitingOoResult.close(...)
      }
    break
    case waitingResult:
      // File saved on QVM is received
      ModuleDocument md = (ModuleDocument)Doc
      if (md and md.isCheckedOut())
      {
         md.setOnlineEditorOpened(false)
         md.setTag("wait_for_result", true)
         this.applyVisibilitiesOnButtonsToolbar()
         WaitingOoResult.showForm(md.DESCRIZIONE)
      }
    break
    case notWaitingResult:
      ModuleDocument md = (ModuleDocument)Doc // File saved on QVM is received
      if (md and md.isCheckedOut())
      {
         md.setOnlineEditorOpened(false)
      }
    break
    case "LOAD":
      MainModule mainModule = (MainModule)Doc
      this.MainModule = mainModule
      if (mainModule)
      {
         mainModule.loadCollectionFromDB(mainModule.ModuleDocuments, ...)
         ModuleDocuments.setCollection(mainModule.ModuleDocuments, true)
      }
    break
    case LOCK_PANELS:
      ModuleDocuments.locked = true
    break
    case UNLOCK_PANELS:
      ModuleDocuments.locked = false
    break
  }
}


// ──────────────────────────────────

// *********************************************************************************
// Event raised by the form object in web applications when a modal window is closed
// *********************************************************************************
event DocComunicazioniSubform.EndModal(
  int LookupForm       // An integer that identifies the modal form that was just closed, using the Me function of the form object to make the comparison.
  boolean Result       // True if the user confirmed the choice, closing the model form using the confirmation button on the title bar; otherwise False. The form can also be closed using the form object's Cl...
  inout boolean Cancel // If set to True, any subsequent automatic processing will be canceled. In this case, the framework will not attempt to automatically transfer the data from the modal form to the call...
)
{
  if (Result)
  {
    if (LookupForm == DocumentiSearch.me())
    {
      int idDocument = DocumentiSearch.Documenti.IDDOCUMENTO
      this.computeModuleDocumentFromTemplate(idDocument)
    }
     
    if (LookupForm == FluidFileUpload.me())
    {
      this.handleFileUpload()
    }
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event DocComunicazioniSubform.ModuleDocuments.OnDynamicProperties()
{
  if (this.MainModule and (!(this.MainModule.isLocked())))
  {
    boolean mainModuleIsInserted = this.MainModule.inserted
    DocCommcommandset.setCommandVisible(Newdocument.getIndex(), !(mainModuleIsInserted))
    DocCommcommandset.setCommandVisible(newFromTemplate.getIndex(), !(mainModuleIsInserted))
     
    if (ModuleDocuments.document)
    {
      ModuleDocument md = ModuleDocuments.document
      boolean documentIsCheckedOut = md.isCheckedOut()
      if (documentIsCheckedOut)
      {
         int yellowColor = RGBColor(243, 250, 170, ...)
         ModuleDocuments.DELETE.backgroundColor = yellowColor
         ModuleDocuments.updownicon.backgroundColor = yellowColor
         ModuleDocuments.IconHtml.backgroundColor = yellowColor
         ModuleDocuments.DESCRGRUPPODOCCOMMGROUP.backgroundColor = yellowColor
         ModuleDocuments.DESCRUTENTECREATORE.backgroundColor = yellowColor
         ModuleDocuments.DESCRUTENTEULTMOD.backgroundColor = yellowColor
         ModuleDocuments.DESCRIZIONE.backgroundColor = yellowColor
         ModuleDocuments.ESTENSIONEFILE.backgroundColor = yellowColor
         ModuleDocuments.DATACREAZIONE.backgroundColor = yellowColor
         ModuleDocuments.IDUTENTEULTMOD.backgroundColor = yellowColor
         ModuleDocuments.DATAULTIMAMOD.backgroundColor = yellowColor
         ModuleDocuments.IDUTENTECREATORE.backgroundColor = yellowColor
         ModuleDocuments.DESCRUTENTEESTR.backgroundColor = yellowColor
         ModuleDocuments.DATAESTRAZIONE.backgroundColor = yellowColor
      }
       
      boolean docInDeletion = md.deleted
      if (docInDeletion)
      {
         int red = RGBColor(250, 130, 172, ...)
         ModuleDocuments.DELETE.backgroundColor = red
         ModuleDocuments.updownicon.backgroundColor = red
         ModuleDocuments.IconHtml.backgroundColor = red
         ModuleDocuments.DESCRGRUPPODOCCOMMGROUP.backgroundColor = red
         ModuleDocuments.DESCRUTENTECREATORE.backgroundColor = red
         ModuleDocuments.DESCRUTENTEULTMOD.backgroundColor = red
         ModuleDocuments.DESCRIZIONE.backgroundColor = red
         ModuleDocuments.ESTENSIONEFILE.backgroundColor = red
         ModuleDocuments.DATACREAZIONE.backgroundColor = red
         ModuleDocuments.IDUTENTEULTMOD.backgroundColor = red
         ModuleDocuments.DATAULTIMAMOD.backgroundColor = red
         ModuleDocuments.IDUTENTECREATORE.backgroundColor = red
         ModuleDocuments.DESCRUTENTEESTR.backgroundColor = red
         ModuleDocuments.DATAESTRAZIONE.backgroundColor = red
      }
    }
  }
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event DocComunicazioniSubform.ModuleDocuments.OnChangeRow()
{
  if (this.MainModule)
  {
    this.applyVisibilitiesOnButtonsToolbar()
  }
}


// ──────────────────────────────────

// *****************************************************
// Raised by the panel when the user double clicks on it
// *****************************************************
event DocComunicazioniSubform.ModuleDocuments.OnMouseDoubleClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  if (Column != -1 and Row != -1)
  {
    ModuleDocument md = ModuleDocuments.document
    if (md and md.IDDOCFILE > 0)
    {
      if (not(md.IDUTENTEESTR > 0))
      {
         if (md.inserted == true)
         {
           UIBusinessLogic.messageBox("Salvare le modifiche prima di aprire il documento.")
         }
         else 
         {
           this.Apri()
         }
      }
      else 
      {
         UIBusinessLogic.messageBox("Il documento selezionato è stato estratto, archiviarlo prima di aprirlo.")
      }
    }
  }
}


// ──────────────────────────────────

// ***********************************************************************
// this procedure applies the visibilities on the buttons of the toolbar. 
// ***********************************************************************
private void DocComunicazioniSubform.applyVisibilitiesOnButtonsToolbar()
{
  DocCommcommandset.setCommandVisible(Apri.getIndex(), false)
  DocCommcommandset.setCommandVisible(Archivia.getIndex(), false)
  DocCommcommandset.setCommandVisible(estraiInModificaWithOO.getIndex(), false)
  DocCommcommandset.setCommandVisible(estraiInModificaWithDownload.getIndex(), false)
  DocCommcommandset.setCommandVisible(undoCheckout.getIndex(), false)
   
  ModuleDocument md = ModuleDocuments.document
  if (md)
  {
    boolean documentIsCheckedOut = md.IDUTENTEESTR > 0
    boolean extractInModificaWithOOIsPossible = md.IsCheckoutWithOOPossible()
    boolean extractInModificaWithDownloadIsPossible = md.isCheckoutWithDownloadPossible()
     
    DocCommcommandset.setCommandVisible(Apri.getIndex(), !(documentIsCheckedOut))
    DocCommcommandset.setCommandVisible(estraiInModificaWithOO.getIndex(), extractInModificaWithOOIsPossible)
    DocCommcommandset.setCommandVisible(estraiInModificaWithDownload.getIndex(), extractInModificaWithDownloadIsPossible)
     
     
    boolean canArchivia = false
    boolean currentMDSupportedByOO = OnlyOfficeTools.extensionIsSupportedByEditor(md.ESTENSIONEFILE)
    if (currentMDSupportedByOO)
      canArchivia = (md.getTag("wait_for_result") != true) and documentIsCheckedOut
    else 
      canArchivia = documentIsCheckedOut
     
    DocCommcommandset.setCommandVisible(Archivia.getIndex(), canArchivia and !(md.isCheckedOutForDownload()))
    DocCommcommandset.setCommandVisible(undoCheckout.getIndex(), documentIsCheckedOut)
  }
   
  if (this.MainModule.isLocked())
  {
    DocCommcommandset.setCommandVisible(Apri.getIndex(), true)
    DocCommcommandset.setCommandVisible(Archivia.getIndex(), false)
    DocCommcommandset.setCommandVisible(estraiInModificaWithOO.getIndex(), false)
    DocCommcommandset.setCommandVisible(estraiInModificaWithDownload.getIndex(), false)
    DocCommcommandset.setCommandVisible(undoCheckout.getIndex(), false)
    DocCommcommandset.setCommandVisible(Newdocument.getIndex(), false)
    DocCommcommandset.setCommandVisible(newFromTemplate.getIndex(), false)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.handleFileUpload()
{
  DocumentUploadHelper duh = this.getObjectTag("documentEdit")
  if (duh and duh.ResultingFilePath != "" and duh.ResultingFilePath != null)
  {
    if (this.InsertTriggered)
    {
      ModuleDocument justCreatedModuleDocument = this.MainModule.addDocComunicazioniFromFile(duh.ResultingFilePath, duh.Description, QappCore.Loggeduser, ..., true)
      justCreatedModuleDocument.saveToDB(...)
       
      this.InsertTriggered = false
       
      string:estraiInModificaModes mode = ""
      if (OnlyOfficeTools.extensionIsSupportedByEditor(justCreatedModuleDocument.ESTENSIONEFILE))
      {
         mode = online_editor
      }
      else 
      {
         mode = download
      }
      justCreatedModuleDocument.checkout(mode, normalMode, this.IDForm())
       
    }
    else 
    {
      ModuleDocument md = ModuleDocuments.document
      if (md)
      {
         md.DESCRIZIONE = duh.Description
         md.checkin(duh.ResultingFilePath)
         md.computeIcon()
      }
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocComunicazioniSubform.callFluidUploadForm(
  boolean isNewFileToBeUploaded          // 
  optional string expectedExtension = "" // 
)
{
  string fileDescription = ""
  boolean enableDescription = true
  IDArray supportedExtensions = new()
  if (!(isNewFileToBeUploaded))
  {
    ModuleDocument md = ModuleDocuments.document
    fileDescription = md.DESCRIZIONE
    enableDescription = false
    supportedExtensions.addValue(expectedExtension)
  }
   
  DocumentUploadHelper duh = DocumentUploadHelper.create(fileDescription, enableDescription, supportedExtensions)
  this.setObjectTag("documentEdit", duh)
  FluidFileUpload.showForm(duh, expectedExtension)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.insertModuleDocument()
{
  this.callFluidUploadForm(true, ...)
  this.InsertTriggered = true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.Apri()
{
  ModuleDocument md = ModuleDocuments.document
  if (md)
  {
    OnlyOfficeDocumentOpener.open(md, this.IDForm(), view)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.Archivia()
{
  // if file extension is supported by OpenOffice (Docx,Doc,Odt,Xlsx etc)
  ModuleDocument md = ModuleDocuments.document
  if (md)
  {
    if (md.isOnlineEditorOpened())
    {
      UIBusinessLogic.messageBox("Il documento è già aperto in una finestra dedicata, chiudila e poi archivia il documento.")
      return 
    }
     
    boolean documentIsSupportedByOO = OnlyOfficeTools.extensionIsSupportedByEditor(md.ESTENSIONEFILE)
    if (documentIsSupportedByOO)
    {
      md.checkin(md.CHECKEDOUTFILE)
      md.saveToDB(...)
       
      // delete file from QVM
      try 
      {
         if (fileExists(md.CHECKEDOUTFILE))
         {
           UIBusinessLogic.deleteFile(md.CHECKEDOUTFILE)
         }
      }
      catch 
      {
         UIBusinessLogic.DTTLogMessage("the file is not removed, not a problem", ...)
      }
    }
    else 
    {
      this.callFluidUploadForm(false, ...)
    }
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.estraiInModificaWithOO()
{
  this.estraiInModifica(online_editor, this.IDForm())
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.estraiInModificaWithDownload()
{
  this.estraiInModifica(download, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.undoCheckout()
{
  int response = UIBusinessLogic.messageConfirmEx("Confermi l'interruzione del processo di estrazione del documento?", "Sì;No")
  if (response != 1)
    return 
   
  ModuleDocument md = ModuleDocuments.document
  if (md)
  {
    md.undoCheckout()
    md.saveToDB(...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.newFromTemplate()
{
  DocumentiSearch.showform(this, Template)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.computeModuleDocumentFromTemplate(
  int idDocument // 
)
{
  Documento modelloDocumento = Documento.getFromDB(idDocument, ...)
  DocumentEngine de = DocumentEngine.create(modelloDocumento, this.MainModule)
  ModuleDocument moduleDocCreated = de.createDocumentFromModello()
  moduleDocCreated.IDUTENTEESTR = QappCore.Loggeduser.IDUTENTE
  moduleDocCreated.DATAESTRAZIONE = now()
  if (moduleDocCreated)
  {
    IDCollection modulesDocuments of ModuleDocument = this.MainModule.ModuleDocuments
    modulesDocuments.add(moduleDocCreated)
    moduleDocCreated.saveToDB(...)
    this.openResultingDocumentFromModello(moduleDocCreated)
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocComunicazioniSubform.updownIcon()
{
  ModuleDocument md = ModuleDocuments.document
   
  if (!(md))
    return 
   
  boolean isCheckedOut = md.isCheckedOut()
   
  if (isCheckedOut)
  {
    this.uploadFile()
  }
  else 
  {
    this.downloadFile(md)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.buttonDelete()
{
  if (!(this.MainModule.isLocked()))
  {
    ModuleDocument md = ModuleDocuments.document
    if (md)
    {
      if (md.isCheckedOut())
      {
         UIBusinessLogic.messageBox("Il documento è estratto in modifica, non è possibile eliminarlo.")
         return 
      }
       
      string confirmationMessage = "Confermi la cancellazione del documento selezionato?"
      int i = UIBusinessLogic.messageConfirmEx(confirmationMessage, "Sì;No")
      if (i == 1)
         md.deleted = true
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.downloadFile(
  ModuleDocument moduleDocument // 
)
{
  int:downloadFileErrorTypes downloadFileError = 0
  string fileToBeDownloaded = moduleDocument.getFilePath(downloadFileError)
  if (downloadFileError == NoError)
  {
    QappCore.OpenDocumentManager.downloadFile(fileToBeDownloaded)
  }
  else 
  {
    UIBusinessLogic.messageBox(formatMessage("Impossibile scaricare il file, errore: |1", decode(downloadFileError, DownloadFileErrorTypes), ...))
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DocComunicazioniSubform.uploadFile()
{
  ModuleDocument md = ModuleDocuments.document
   
  if (md)
  {
    if (!(md.isCheckedOutForDownload()))
    {
      UIBusinessLogic.messageBox("Il documento è stato estratto nel browser, non è possibile fare l'upload del file.")
      return 
    }
  }
   
  this.callFluidUploadForm(false, md.ESTENSIONEFILE)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ClosePromemoriaModal.showForm(
  Promemoria promemoria // Write a comment for this parameter or press backspace to delete this comment
)
{
  Promemoria.setDocument(promemoria, true)
  Promemoria.Labellabelconfirmation.text = promemoria.getClosureConfirmationMessage()
  promemoria.ESITO = Positive
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event ClosePromemoriaModal.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm)
  {
    Promemoria p = Promemoria.document
     
    // we explicitly call close (even if in the modal form NOTECHIUSURA and ESITO were alerady set) so we can later centralize in it notification events
    p.close(p.NOTECHIUSURA, p.ESITO == Positive)
//    p.saveToDB(...)
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event CustomDataSubform.Load()
{
  this.formHandledKeys = KeyNone | KeysEnterEsc | KeysMovement | KeysAlphaNumerical
  Customdata.panelWidth = 1000
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event CustomDataSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
   
  switch (Message)
  {
    case "LOAD":
      this.loadCustomData(Doc, Par1, Par4, false)
    break
    case "SHOWERRORS":
      UICustomDataCentralizedTools.ShowErrorsInCustomDataPanel(Customdata.IDPanel(), this.MainModule)
    break
    case "setLookupResults":
      int selectedId = toInteger(Par1)
      string selectedValueLookupDescription = Par2
      UIBusinessLogic.DTTLogMessage("par2 contains the decoded value we never use it since decoding is done again in the methods called below: " +
            selectedValueLookupDescription, ..., DTTInfo)
      string fieldCode = Par3
      RenderingHelper rh = Customdata.document
       
      int fieldIndex = toInteger(replace(fieldCode, "VALUE", ""))
       
      DatoPersonalizzatoInfo dpi = (DatoPersonalizzatoInfo)rh.CdataMapping.getObject(fieldCode)
       
      rh.updateRenderingHelperProperty(dpi, fieldIndex, toString(selectedId))
      rh.updateDatoPersonalizzatoInOwner(fieldIndex)
    break
    case "GET_RENDERED_CDATA_COUNT":
      Sender.sendMessage("RETURN_RENDERED_CDATA_COUNT", null, toString(this.CustomDataRenderingHelper.RenderedFieldsCount), ...)
    break
    case UNLOCK_PANELS:
    case LOCK_PANELS:
      boolean enablePanelFields = Message == UNLOCK_PANELS
       
      IDPanel idp = Customdata.IDPanel()
      for (int i = 0; i < idp.fieldsCount(); i = i + 1)
      {
         idp.setFieldEnabled(i, enablePanelFields)
      }
    break
  }
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event CustomDataSubform.Customdata.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
//)
//{
//  this.handleMouseClick(Column)
//}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event CustomDataSubform.Customdata.OnDynamicProperties()
{
  RenderingHelper rh = Customdata.document
  if (!(rh))
  {
    return 
  }
   
  DatoPersonalizzatoInfo dpi1 = (DatoPersonalizzatoInfo)rh.CdataMapping.getObject("VALUE1")
   
  DatoPersonalizzatoInfo dpi2 = (DatoPersonalizzatoInfo)rh.CdataMapping.getObject("VALUE2")
   
  DatoPersonalizzatoInfo dpi3 = (DatoPersonalizzatoInfo)rh.CdataMapping.getObject("VALUE3")
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value1.OnButtonClicked(
  object info // What is this parameter for?
)
{
   
   
  this.onButtonClickEventHandler(info, 1)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value2.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 2)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value3.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 3)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value4.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 4)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value5.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 5)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value7.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 7)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value8.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 8)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value9.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 9)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value10.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 10)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value11.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 11)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value12.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 12)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value13.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 13)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value14.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 14)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value15.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 15)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value16.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 16)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value17.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 17)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value18.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 18)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value19.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 19)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value20.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 20)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value21.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 21)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value22.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 22)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value23.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 23)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value24.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 24)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value25.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 25)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value26.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 26)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value27.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 28)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value29.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 29)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value30.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 30)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value31.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 31)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value32.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 32)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value33.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 33)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value34.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 34)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value35.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 35)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value36.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 36)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value37.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 37)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value39.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 39)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value40.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 40)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value41.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 41)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value42.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 42)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value43.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 43)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value44.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 44)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value45.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 45)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value46.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 46)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value47.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 47)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value48.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 48)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value49.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 49)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value50.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 50)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value52.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 52)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value53.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 53)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value54.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 54)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value56.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 56)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value57.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 57)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value58.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 58)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value59.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 59)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value60.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 60)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value61.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 61)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value62.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 62)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value63.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 63)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value64.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 64)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value66.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 66)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value67.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 67)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value68.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 68)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value70.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 70)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value71.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 71)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value72.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 72)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value73.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 73)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value74.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 74)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value75.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 75)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value77.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 77)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value79.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 79)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value80.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 80)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value81.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 81)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value82.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 82)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value83.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 83)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value84.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 84)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value85.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 85)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value87.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 87)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value88.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 88)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value89.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 89)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value90.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 90)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value91.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 91)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value92.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 92)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value93.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 93)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value94.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 94)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value95.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 95)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value96.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 96)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value97.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 97)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value98.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 98)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value99.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 99)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value100.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 100)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value101.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 101)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value102.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 102)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value103.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 103)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value104.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 104)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value105.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 105)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value106.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 106)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value107.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 107)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value108.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 108)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value109.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 109)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value110.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 110)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value111.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 111)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value112.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 112)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value113.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 113)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value114.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 114)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value115.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 115)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value116.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 116)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value117.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 117)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value118.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 118)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value120.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 120)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value121.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 121)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value122.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 122)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value123.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 123)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value124.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 124)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value125.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 125)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value126.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 126)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value127.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 127)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value128.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 128)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value129.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 129)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value130.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 130)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value131.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 131)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value132.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 132)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value133.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 133)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value134.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 134)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value135.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 135)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value136.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 136)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value138.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 138)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value140.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 140)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value141.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 141)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value142.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 141)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value143.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 143)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value144.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 144)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value145.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 145)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value146.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 146)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value147.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 147)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value148.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 148)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value149.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 149)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value150.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 150)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value151.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 151)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value152.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 152)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value153.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 153)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value154.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 154)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value155.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 155)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value156.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 156)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value157.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 158)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value158.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 158)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value159.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 159)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value160.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 160)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value161.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 161)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value162.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 162)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value164.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 164)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value165.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 165)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value167.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 167)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value168.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 168)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value169.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 169)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value170.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 170)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value171.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 171)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value172.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 172)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value173.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 173)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value174.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 174)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value176.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 176)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value177.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 177)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value178.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 178)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value179.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 179)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value180.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 180)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value181.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 181)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value182.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 182)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value183.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 183)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value184.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 184)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value185.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 185)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value186.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 186)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value187.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 187)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value188.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 188)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value189.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 189)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value190.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 190)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value191.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 191)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value192.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 192)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value193.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 193)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value194.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 194)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value195.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 195)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value196.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 196)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value197.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 197)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value198.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 198)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value199.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 199)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value200.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 200)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value201.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 201)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value203.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 203)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value204.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 204)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value205.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 205)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value206.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 206)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value207.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 207)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value208.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 208)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value209.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 209)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value210.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 210)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value211.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 211)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value212.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 212)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value213.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 213)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value214.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 214)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value215.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 215)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value216.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 216)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value217.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 217)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value218.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 218)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value219.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 219)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value220.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 220)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value221.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 221)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value222.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 222)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value223.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 223)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value224.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 224)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value225.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 225)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value226.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 226)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value227.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 227)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value228.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 228)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value231.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 231)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value232.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 231)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value233.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 233)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value234.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 234)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value235.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 235)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value236.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 236)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value237.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 237)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value238.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 238)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value239.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 239)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value240.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 240)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value241.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 241)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value242.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 242)
}


// ──────────────────────────────────



// ──────────────────────────────────

event CustomDataSubform.Customdata.Value244.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 244)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value245.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 245)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value246.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 246)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value247.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 247)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value248.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 248)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value249.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 249)
}


// ──────────────────────────────────

event CustomDataSubform.Customdata.Value250.OnButtonClicked(
  object info // What is this parameter for?
)
{
  this.onButtonClickEventHandler(info, 250)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void CustomDataSubform.loadCustomData(
  IDDocument Doc                                     // 
  optional string renderOnlyMandatoryCdata = "false" // 
  optional string idResult = ""                      // 
  optional boolean forceReloading = 0                // 
)
{
  if (MainModule.isMyInstance(Doc))
  {
    MainModule mainmodule = (MainModule)Doc
     
    // store the form variable
    this.MainModule = mainmodule
     
    if ((mainmodule != null) or forceReloading)
    {
      if (mainmodule.DatiPersonalizzati.count() == 0 or forceReloading)
      {
         mainmodule.DatiPersonalizzati.clear()
         mainmodule.loadDatiPers()
      }
       
      if (idResult != "")
      {
         this.CustomDataRenderingHelper = RenderingHelper.factory(WkfResultLayout, mainmodule, Customdata.IDPanel(), 50, ...)
      }
      else 
      {
         this.CustomDataRenderingHelper = RenderingHelper.factory(FormLayout, mainmodule, Customdata.IDPanel(), 50, ...)
      }
       
      boolean shouldRenderOnlyMandatoryCdata = renderOnlyMandatoryCdata == "true"
      this.CustomDataRenderingHelper.prepareAndRender(shouldRenderOnlyMandatoryCdata, ..., idResult)
       
      if (this.CustomDataRenderingHelper.FieldLimitExceededWhileRendering)
         UIBusinessLogic.messageBox(this.CustomDataRenderingHelper.composeFieldLimitExceedWarningMessage())
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void CustomDataSubform.handleMouseClick(
  int Column // 
)
{
  RenderingHelper ch = Customdata.document
  int clickedColumn = Column
  if (ch and clickedColumn >= 0)
  {
    string keyValue = "VALUE" + toString(clickedColumn + 1)
    this.setTag("clickedFieldCode", keyValue)
    if (ch)
    {
      MainModuleDatoPersonalizzatoInfo cfi = (MainModuleDatoPersonalizzatoInfo)ch.CdataMapping.getObject(keyValue)
      int:kordapp matchingKordApp = MainModuleDatoPersonalizzatoInfo.getKordAppFromModuleTypeCustomDataType(cfi.Type)
      if (matchingKordApp > 0)
      {
         this.openLookupForm(cfi, keyValue, matchingKordApp)
      }
    }
     
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CustomDataSubform.openLookupForm(
  MainModuleDatoPersonalizzatoInfo cfi // 
  string keyvalue                      // 
  int:kordapp kordApp                  // 
)
{
  boolean showContattiLookup = cfi.Type == ContattoCDataType
  LookupHelper lookupHelper = LookupHelper.create(this.IDForm(), kordApp, false, ..., keyvalue, if(showContattiLookup, Contatto.className(...), ""))
  lookupHelper.displayLookup()
   
   
}


// ──────────────────────────────────

// ***************************************************************
// centralized event handler for the On Button Click of all fields
// the parameter allows to map the method to the caller field
// ***************************************************************
public void CustomDataSubform.onButtonClickEventHandler(
  object info    // 
  int fieldIndex // 
)
{
  // info JSON contains
  IDMap idm = cast(info)
   
   
  RenderingHelper rh = Customdata.document
  string key = formatMessage("VALUE|1", fieldIndex, ...)
  MainModuleDatoPersonalizzatoInfo dpi = (MainModuleDatoPersonalizzatoInfo)rh.CdataMapping.getObject(key)
   
  // the passed json contains the buttonType property to tell the backend which button has been clicked
  string:clickedButtonTypes clickedButtonType = idm.getValue("buttonType")
  switch (clickedButtonType)
  {
    case open:
      MainModule mm = rh.tryRetrieveMainModuleSetInModuleTypeRenderingHelperProperty(fieldIndex)
      if (mm)
         mm.openDetailForm()
    break
    case lookup:
      int:kordapp matchingKordApp = MainModuleDatoPersonalizzatoInfo.getKordAppFromModuleTypeCustomDataType(dpi.Type)
      if (matchingKordApp > 0)
         this.openLookupForm(dpi, key, matchingKordApp)
    break
    default:
      UIBusinessLogic.DTTLogMessage("BUTTON TYPE NOT SUPPORTED", ..., DTTError)
    break
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean CustomDataSubform.validateCustomData()
{
  return this.CustomDataRenderingHelper.ValidateRenderedDatiPers()
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event MainCollegamentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "LOAD":
       
      if (MainModule.isMyInstance(Doc))
      {
         this.MainModule = (MainModule)Doc
         if (this.MainModule)
         {
           this.MainModule.loadCollegamenti(...)
           this.attachCollegamenti()
         }
      }
    break
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MainCollegamentiSubform.attachCollegamenti()
{
  CollegamentiSubtabSubform referenceLinks = null
  CollegamentiSubtabSubform customDataLinks = null
  DiscussionsSubform discussionLinks = null
  CollegamentiSubtabSubform qappdataLinks = null
   
  if (this.MainModule.CollegamentoRiferimento.count() > 0)
  {
    referenceLinks = CollegamentiSubtabSubform.newInstance(SubForm, ...)
    MainCollegamentiTabbedView.addForm(referenceLinks)
    int formPageIndex = MainCollegamentiTabbedView.getFormPageIndex(referenceLinks)
    MainCollegamentiTabbedView.setCaption(formPageIndex, "Riferirmenti")
    referenceLinks.sendMessage("LOAD_REFERENCES", this.MainModule, ...)
  }
  if (this.MainModule.CollegamentoCustomData.count() > 0)
  {
    customDataLinks = CollegamentiSubtabSubform.newInstance(SubForm, ...)
    MainCollegamentiTabbedView.addForm(customDataLinks)
    int formPageIndex = MainCollegamentiTabbedView.getFormPageIndex(customDataLinks)
    MainCollegamentiTabbedView.setCaption(formPageIndex, "Dati Personalizzati")
    customDataLinks.sendMessage("LOAD_CUSTOMDATA", this.MainModule, ...)
  }
  if (this.MainModule.CollegamentoDiscussion.count() > 0)
  {
    discussionLinks = DiscussionsSubform.newInstance(SubForm, ...)
    MainCollegamentiTabbedView.addForm(discussionLinks)
    int formPageIndex = MainCollegamentiTabbedView.getFormPageIndex(discussionLinks)
    MainCollegamentiTabbedView.setCaption(formPageIndex, "Discussioni")
    discussionLinks.sendMessage("LOAD", this.MainModule, ...)
  }
  if (this.MainModule.CollegamentoQappData.count() > 0)
  {
    qappdataLinks = CollegamentiSubtabSubform.newInstance(SubForm, ...)
    MainCollegamentiTabbedView.addForm(qappdataLinks)
    int formPageIndex = MainCollegamentiTabbedView.getFormPageIndex(qappdataLinks)
    MainCollegamentiTabbedView.setCaption(formPageIndex, "QApp")
    qappdataLinks.sendMessage("LOAD_QAPPDATA", this.MainModule, ...)
  }
  if (MainCollegamentiTabbedView.pagesCount() > 0)
  {
    MainCollegamentiTabbedView.moveTo(0)
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event CollegamentiSubtabSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "LOAD_REFERENCES":
       
      if (MainModule.isMyInstance(Doc))
      {
         this.MainModule = (MainModule)Doc
         if (this.MainModule)
         {
           this.attachReferenceCollegamenti()
         }
      }
    break
    case "LOAD_CUSTOMDATA":
       
      if (MainModule.isMyInstance(Doc))
      {
         this.MainModule = (MainModule)Doc
         if (this.MainModule)
         {
           this.attachCustomDataCollegamenti()
         }
      }
    break
    case "LOAD_DISCUSSIONS":
       
      if (MainModule.isMyInstance(Doc))
      {
         this.MainModule = (MainModule)Doc
         if (this.MainModule)
         {
           this.attachDiscussionCollegamenti()
         }
      }
    break
    case "LOAD_QAPPDATA":
       
      if (MainModule.isMyInstance(Doc))
      {
         this.MainModule = (MainModule)Doc
         if (this.MainModule)
         {
           this.attachQappDataCollegamenti()
         }
      }
    break
  }
   
  if (TabbedView.pagesCount() > 0)
  {
    TabbedView.moveTo(0)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CollegamentiSubtabSubform.attachReferenceCollegamenti()
{
  IDCollection coll of ReferenceType = new()
  IDArray ida = this.MainModule.CollegamentiRiferimentoTypes.getKeys()
  for (int i = 0; i < ida.length(); i = i + 1)
  {
    int IdRreferenceType = toInteger(ida.getValue(i))
    ReferenceType rt = ReferenceType.get(IdRreferenceType)
    coll.addRef(rt)
  }
   
  ReferenceType rt1 = new()
  int propertyIndexDescription = rt1.getPropertyIndex("LINKSTABNAME", true, true, true, true)
  coll.addSortCriteria(propertyIndexDescription)
  coll.doSort()
  for each ReferenceType rt in coll
  {
    this.attachCollegamentiSubform(rt.LinksTabName, rt.DestinationKordapp, rt.IDTipoRiferimento, References)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CollegamentiSubtabSubform.attachCollegamentiSubform(
  string tabCaption                                  // Write a comment for this parameter or press backspace to delete this comment
  int:kordapp kord                                   // 
  int type                                           // 
  string:collegamentiMainmoduleType collegamentiType // 
)
{
  IDForm idf = null
  switch (collegamentiType)
  {
    case References:
    case CustomData:
      idf = createMainModuleSubformInstance(kord)
    break
    case Qappdata:
      idf = createQappdataSubformInstance()
    break
    case Discussion:
      idf = createDiscussionSubformInstance()
    break
  }
  TabbedView.addForm(idf)
  int formPageIndex = TabbedView.getFormPageIndex(idf)
  TabbedView.setCaption(formPageIndex, tabCaption)
  idf.sendMessage("LOAD", this.MainModule, toString(type), collegamentiType, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm CollegamentiSubtabSubform.createMainModuleSubformInstance(
  int:kordapp kord // 
)
{
  IDForm moduleSubform = null
  switch (kord)
  {
    case Eventi:
      EventiCollegamentiSubform subform = EventiCollegamentiSubform.newInstance(SubForm, ...)
      moduleSubform = subform
    break
    case Personale:
      PersonaleCollegamentiSubform subform = PersonaleCollegamentiSubform.newInstance(SubForm, ...)
      moduleSubform = subform
    break
    case Articoli:
      ArticoliCollegamentiSubform subform = ArticoliCollegamentiSubform.newInstance(SubForm, ...)
      moduleSubform = subform
    break
    case AltreAnagrafiche:
      AltreAnagraficheCollegamentiSubform subform = AltreAnagraficheCollegamentiSubform.newInstance(SubForm, ...)
      moduleSubform = subform
    break
    case Privati:
      PrivatiCollegamentiSubform subform = PrivatiCollegamentiSubform.newInstance(SubForm, ...)
      moduleSubform = subform
    break
    case Funzioni:
      FunzioniCollegamentiSubform subform = FunzioniCollegamentiSubform.newInstance(SubForm, ...)
      moduleSubform = subform
    break
    case Progetti:
      ProgettiCollegamentiSubform subform = ProgettiCollegamentiSubform.newInstance(SubForm, ...)
      moduleSubform = subform
    break
    case ClientiFornitori:
      ClientiFornitoriCollegamentiSubform subform = ClientiFornitoriCollegamentiSubform.newInstance(SubForm, ...)
      moduleSubform = subform
    break
    case Interventi:
      InterventiCollegamentiSubform subform = InterventiCollegamentiSubform.newInstance(SubForm, ...)
      moduleSubform = subform
    break
  }
  return moduleSubform
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CollegamentiSubtabSubform.attachCustomDataCollegamenti()
{
  IDArray arrayToSortKords = new()
  IDMap kordMapping = new()
  IDArray ida = this.MainModule.CollegamentiCustomDataKords.getKeys()
  for (int i = 0; i < ida.length(); i = i + 1)
  {
    int kord = toInteger(ida.getValue(i))
    string decodedKord = decode(kord, Kordapp)
    arrayToSortKords.addValue(decodedKord)
    kordMapping.setValue(decodedKord, kord)
  }
   
  arrayToSortKords.sort()
   
  for (int j = 0; j < arrayToSortKords.length(); j = j + 1)
  {
    string decodedKord = arrayToSortKords.getValue(j)
    int kordID = kordMapping.getValue(decodedKord)
    this.attachCollegamentiSubform(decodedKord, kordID, kordID, CustomData)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CollegamentiSubtabSubform.attachDiscussionCollegamenti()
{
   
  this.attachCollegamentiSubform("Discussioni", Messaggi, 0, Discussion)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm CollegamentiSubtabSubform.createDiscussionSubformInstance()
{
  DiscussionsSubform discussionSubform = DiscussionsSubform.newInstance(SubForm, ...)
  return discussionSubform
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDForm CollegamentiSubtabSubform.createQappdataSubformInstance()
{
  QappdataCollegamentoSubform qappdataSubform = QappdataCollegamentoSubform.newInstance(SubForm, ...)
  return qappdataSubform
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CollegamentiSubtabSubform.attachQappDataCollegamenti()
{
  IDArray idApplicationKeys = this.MainModule.CollegamentiQappData.getKeys()
  IDCollection coll of NGTAPPLICAZIONI = new()
  for (int i = 0; i < idApplicationKeys.length(); i = i + 1)
  {
    int idApplicationKey = toInteger(idApplicationKeys.getValue(i))
    try 
    {
      NGTAPPLICAZIONI ngtapplicazioni = NGTAPPLICAZIONI.getFromDb(idApplicationKey)
      coll.add(ngtapplicazioni)
    }
  }
   
  NGTAPPLICAZIONI ngtapplicazioni1 = new()
  int j = ngtapplicazioni1.getPropertyIndex("DESCRAPPLICA", true, true, true, true)
  coll.addSortCriteria(j)
  coll.doSort()
  for each NGTAPPLICAZIONI ngtapplicazioni in coll
  {
    this.attachCollegamentiSubform(ngtapplicazioni.DESCRAPPLICAZIONE, ngtapplicazioni.IDAPPLICAZIONE, ngtapplicazioni.IDAPPLICAZIONE, Qappdata)
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event EventiCollegamentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD")
  {
    this.MainModule = (MainModule)Doc
    if (this.MainModule)
    {
      int typeID = toInteger(Par1)
      string:collegamentiMainmoduleType cmt = Par2
      IDCollection coll of CollegamentoMainModule = this.MainModule.retrieveMainModuleCollegamentiCollection(typeID, cmt)
      Eventi.setCollection(coll, true)
    }
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event EventiCollegamentiSubform.Eventi.OnDynamicProperties()
{
  CollegamentoEvento ce = Eventi.document
  if (ce and ce.IDEVENTO > 0)
  {
    Eventi.IDEVENTO.backgroundColor = ce.BackgroundColor
    Eventi.NROEVENTO.backgroundColor = ce.BackgroundColor
    Eventi.IDSTATOEVENTO.backgroundColor = ce.BackgroundColor
    Eventi.DESCRTITOLO.backgroundColor = ce.BackgroundColor
    Eventi.DATAEVENTO.backgroundColor = ce.BackgroundColor
    Eventi.IDCLASSE.backgroundColor = ce.BackgroundColor
    Eventi.IDAMBITO.backgroundColor = ce.BackgroundColor
    Eventi.IDTIPOLOGIA.backgroundColor = ce.BackgroundColor
    Eventi.IDGRAVITA.backgroundColor = ce.BackgroundColor
    Eventi.DESCREVENTOTXT.backgroundColor = ce.BackgroundColor
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event PersonaleCollegamentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD")
  {
    this.MainModule = (MainModule)Doc
    if (this.MainModule)
    {
      int typeID = toInteger(Par1)
      string:collegamentiMainmoduleType cmt = Par2
      IDCollection coll of CollegamentoMainModule = this.MainModule.retrieveMainModuleCollegamentiCollection(typeID, cmt)
      Personale.setCollection(coll, true)
    }
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event ArticoliCollegamentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD")
  {
    this.MainModule = (MainModule)Doc
    if (this.MainModule)
    {
      int typeID = toInteger(Par1)
      string:collegamentiMainmoduleType cmt = Par2
      IDCollection coll of CollegamentoMainModule = this.MainModule.retrieveMainModuleCollegamentiCollection(typeID, cmt)
      Articoli.setCollection(coll, true)
    }
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event AltreAnagraficheCollegamentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD")
  {
    this.MainModule = (MainModule)Doc
    if (this.MainModule)
    {
      int typeID = toInteger(Par1)
      string:collegamentiMainmoduleType cmt = Par2
      IDCollection coll of CollegamentoMainModule = this.MainModule.retrieveMainModuleCollegamentiCollection(typeID, cmt)
      AltreAnagrafiche.setCollection(coll, true)
    }
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event PrivatiCollegamentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD")
  {
    this.MainModule = (MainModule)Doc
    if (this.MainModule)
    {
      int typeID = toInteger(Par1)
      string:collegamentiMainmoduleType cmt = Par2
      IDCollection coll of CollegamentoMainModule = this.MainModule.retrieveMainModuleCollegamentiCollection(typeID, cmt)
      Privati.setCollection(coll, true)
    }
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event FunzioniCollegamentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD")
  {
    this.MainModule = (MainModule)Doc
    if (this.MainModule)
    {
      int typeID = toInteger(Par1)
      string:collegamentiMainmoduleType cmt = Par2
      IDCollection coll of CollegamentoMainModule = this.MainModule.retrieveMainModuleCollegamentiCollection(typeID, cmt)
      Funzioni.setCollection(coll, true)
    }
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event ClientiFornitoriCollegamentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD")
  {
    this.MainModule = (MainModule)Doc
    if (this.MainModule)
    {
      int typeID = toInteger(Par1)
      string:collegamentiMainmoduleType cmt = Par2
      IDCollection coll of CollegamentoMainModule = this.MainModule.retrieveMainModuleCollegamentiCollection(typeID, cmt)
      ClientiFornitori.setCollection(coll, true)
    }
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event InterventiCollegamentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD")
  {
    this.MainModule = (MainModule)Doc
    if (this.MainModule)
    {
      int typeID = toInteger(Par1)
      string:collegamentiMainmoduleType cmt = Par2
      IDCollection coll of CollegamentoMainModule = this.MainModule.retrieveMainModuleCollegamentiCollection(typeID, cmt)
      Interventi.setCollection(coll, true)
    }
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event DiscussionsSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD")
  {
    this.MainModule = (MainModule)Doc
    if (this.MainModule)
    {
      UIBusinessLogic.DTTLogMessage(this.MainModule.CollegamentoDiscussion.count(), 161616, ...)
      MSGMESSAGGI.setCollection(this.MainModule.CollegamentoDiscussion, true)
    }
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event QappdataCollegamentoSubform.NGTQAPPSDATA.OnDynamicProperties()
{
  CollegamentoQappdata cq = NGTQAPPSDATA.document
  if (cq and cq.IDAPPLICAZIONE > 0)
  {
     
    NGTQAPPSDATA.DATE.backgroundColor = cq.BackgroundColor
    NGTQAPPSDATA.DESCRIPTION.backgroundColor = cq.BackgroundColor
    NGTQAPPSDATA.DETAIL.backgroundColor = cq.BackgroundColor
    NGTQAPPSDATA.IDAPPLICAZIONE.backgroundColor = cq.BackgroundColor
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event RiferimentiSubform.Load()
{
  this.ClickedX = UIBusinessLogic.screenWidth / 2
  this.ClickedY = UIBusinessLogic.screenHeight / 2
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event RiferimentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "LOAD":
      MainModule mainModule = (MainModule)Doc
      this.MainModule = mainModule
       
      if (this.MainModule)
         this.AttachReferencesTabs(this.MainModule)
    break
    case "NEW_REFERENCE_TYPE_SELECTED":
      ReferenceType rt = (ReferenceType)Doc
      this.selectreference(rt)
    break
    case "setLookupResults":
      int selectedId = toInteger(Par1)
      this.applyLookupSelection(selectedId)
    break
    case UNLOCK_PANELS:
    case LOCK_PANELS:
      refCommandset.visible = Message == UNLOCK_PANELS
      IDArray ida = this.SubformsMap.getKeys()
      for (int i = 0; i < this.SubformsMap.length(); i = i + 1)
      {
         string key = ida.getValue(i)
         IDForm idf = (IDForm)this.SubformsMap.getObject(key)
         idf.sendMessage(Message, ...)
      }
    break
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void RiferimentiSubform.AttachReferencesTabs(
  MainModule mainModule // 
)
{
  if (mainModule.Riferimenti.count() == 0)
  {
    mainModule.loadCollectionFromDB(mainModule.Riferimenti, ...)
  }
   
  IDCollection sortedRefTypes of ReferenceType = getSortedReferenceTypesFromReferences(mainModule)
  int count = 0
  for each ReferenceType rt in sortedRefTypes
  {
    boolean focusOnTheTab = count == 0
    this.attachATab(rt, focusOnTheTab)
    count = count + 1
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void RiferimentiSubform.selectreference(
  ReferenceType referenceType // 
)
{
  this.SelectedReferenceTypeForInsertion = referenceType
  this.openLookupForm(referenceType.SourceKordapp, referenceType.IDTipoRiferimento)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void RiferimentiSubform.attachATab(
  ReferenceType rt      // 
  boolean focusOnTheTab // 
)
{
  RiferimentiSingleTabContentSubform r = RiferimentiSingleTabContentSubform.newSubForm()
  RiferimentiTabbedView.addForm(r)
  this.SubformsMap.setObject(rt.IDTipoRiferimento, r)
  int i = RiferimentiTabbedView.getFormPageIndex(r)
  RiferimentiTabbedView.setCaption(i, rt.Name)
  if (focusOnTheTab)
  {
    RiferimentiTabbedView.selectPage(i)
  }
  r.visible = !(rt.hidden)
  r.sendMessage("LOAD", this.MainModule, rt.IDTipoRiferimento, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public IDCollection RiferimentiSubform.getSortedReferenceTypesFromReferences(
  MainModule mainModule // 
)
{
  IDMap referenceTypesMap = new()
   
  IDCollection sortedRefTypes of ReferenceType = new()
   
  for each Riferimento r in mainModule.Riferimenti
  {
    if (!(referenceTypesMap.containsKey(r.IDTipoRiferimento)))
    {
      ReferenceType rt = ReferenceType.get(r.IDTipoRiferimento)
      if (rt.ATTIVO == Yes)
      {
         sortedRefTypes.add(rt)
         referenceTypesMap.setValue(r.IDTipoRiferimento, true)
      }
    }
  }
   
  sortedRefTypes.moveFirst()
   
  ReferenceType refTypeToFindIndex = new()
   
  int seqPropertyIndex = refTypeToFindIndex.getPropertyIndex("SEQUENZA", false, false, true, ...)
  int namePropertyIndex = refTypeToFindIndex.getPropertyIndex("REF_NAME", false, false, true, ...)
  sortedRefTypes.addSortCriteria(seqPropertyIndex)
  sortedRefTypes.addSortCriteria(namePropertyIndex)
  sortedRefTypes.doSort()
   
  return sortedRefTypes
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void RiferimentiSubform.openLookupForm(
  int:kordapp lookupFormKordapp // 
  int referredId                // 
)
{
  ReferenceType rt = ReferenceType.get(referredId)
  if (rt)
  {
    LookupHelper lh = LookupHelper.create(this, lookupFormKordapp, false, rt, ...)
    lh.displayLookup()
  }
   
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void RiferimentiSubform.insertIntoExistingRefTab(
  Riferimento riferimento // 
)
{
  RiferimentiSingleTabContentSubform r2 = (RiferimentiSingleTabContentSubform)this.SubformsMap.getObject(this.SelectedReferenceTypeForInsertion.IDTipoRiferimento)
  r2.addRiferimentiInPanelCollection(riferimento)
  int i = RiferimentiTabbedView.getFormPageIndex(r2)
  RiferimentiTabbedView.selectPage(i)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void RiferimentiSubform.NewReference()
{
  UIBusinessLogic.ReferenceTypeMenuController.openPopupMenu(this.MainModule, this.IDForm(), newreference.getRD3ID())
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void RiferimentiSubform.applyLookupSelection(
  int selectedId // 
)
{
  string:flagYN isModello = No
  if (ModelloEvento.isMyInstance(this.MainModule))
  {
    isModello = Yes
  }
  if (this.SelectedReferenceTypeForInsertion and this.SelectedReferenceTypeForInsertion.IDTipoRiferimento > 0)
  {
    Riferimento r = Riferimento.create(this.SelectedReferenceTypeForInsertion.IDTipoRiferimento, this.MainModule.getMainID(), selectedId, isModello)
    r.DestinationDescription = r.getDestinationDescription()
    MainModule.Riferimenti.add(r)
     
    if (!(this.SubformsMap.containsKey(this.SelectedReferenceTypeForInsertion.IDTipoRiferimento)))
    {
      // attach a new tab
      this.attachATab(this.SelectedReferenceTypeForInsertion, true)
    }
    else 
    {
      this.insertIntoExistingRefTab(r)
    }
    r.inserted = true
    this.SelectedReferenceTypeForInsertion = null
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event RiferimentiSingleTabContentSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "LOAD":
      this.loadData(Doc, Par1)
    break
    case "setLookupResults":
      int id = toInteger(Par1)
      boolean isContatto = Par4 == "contatti"
      RiferimentoRenderingHelper r = RiferimentiRenderingHelper.document
      r.updateOwnerValues(isContatto, id, Par2)
    break
    case UNLOCK_PANELS:
    case LOCK_PANELS:
      boolean enablePanelFields = Message == UNLOCK_PANELS
       
      IDPanel idp = RiferimentiRenderingHelper.IDPanel()
      for (int i = 0; i < idp.fieldsCount(); i = i + 1)
      {
         idp.setFieldEnabled(i, enablePanelFields)
      }
    break
  }
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event RiferimentiSingleTabContentSubform.RiferimentiRenderingHelper.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  RenderingHelper ch = RiferimentiRenderingHelper.document
  int clickedColumn = Column
  if (ch and clickedColumn >= 0)
  {
    string keyValue = "VALUE" + toString(clickedColumn + 1)
    this.setTag("clickedFieldCode", keyValue)
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void RiferimentiSingleTabContentSubform.addRiferimentiInPanelCollection(
  Riferimento riferimento // 
)
{
  IDCollection coll of RiferimentoRenderingHelper = RiferimentiRenderingHelper.collection
   
  IDPanel idp = RiferimentiRenderingHelper.IDPanel()
   
  RiferimentoRenderingHelper rrh = RiferimentoRenderingHelper.create(riferimento, idp, ...)
  riferimento.SetRenderingHelper(rrh)
   
  coll = RiferimentoRenderingHelper.addIntoExistingCollection(coll, rrh)
  rrh.initializePropertiesFromMapping()
  RiferimentiRenderingHelper.setCollection(coll, ...)
  idp.calcLayout()
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void RiferimentiSingleTabContentSubform.loadData(
  IDDocument Doc     // 
  string otherParams // 
)
{
  if (MainModule.isMyInstance(Doc))
  {
    MainModule mainmodule = (MainModule)Doc
     
    // store the form variable
    this.MainModule = mainmodule
     
    if (mainmodule and this.getTag("Loaded") != true)
    {
      boolean renderMandatoryOnly = 0
      this.CustomDataRenderingHelper = RenderingHelper.factory(ListLayout, Doc, RiferimentiRenderingHelper.IDPanel(), ...)
       
      this.CustomDataRenderingHelper.prepareAndRender(renderMandatoryOnly, toInteger(otherParams), ...)
       
      if (this.CustomDataRenderingHelper.FieldLimitExceededWhileRendering)
         UIBusinessLogic.messageBox(this.CustomDataRenderingHelper.composeFieldLimitExceedWarningMessage())
       
      this.setTag("Loaded", true)
       
      if (this.MainModule.isLocked())
      {
         RiferimentiRenderingHelper.Destinazione.setEnabled(false)
         RiferimentiRenderingHelper.Header2.setEnabled(false)
         RiferimentiRenderingHelper.DELETE.setEnabled(false)
      }
    }
  }
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void RiferimentiSingleTabContentSubform.selectContatto()
{
  RiferimentoRenderingHelper renderingHelper = RiferimentiRenderingHelper.document
  if (renderingHelper)
  {
    Riferimento r = cast(renderingHelper.getOwner())
    if (r.ReferenceType.SourceKordapp == ClientiFornitori)
    {
      LookupHelper lh = LookupHelper.create(this, ..., false, r.ReferenceType, Contatto.className(...), r.IDForAll)
      lh.displayLookup()
    }
    if (r.ReferenceType.SourceKordapp == AltreAnagrafiche)
    {
      LookupHelper lh = LookupHelper.create(this, ..., false, r.ReferenceType, Intervento.className(...), r.IDForAll)
      lh.displayLookup()
    }
     
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void RiferimentiSingleTabContentSubform.delete()
{
  if (!(this.MainModule.isLocked()))
  {
    RiferimentoRenderingHelper r = RiferimentiRenderingHelper.document
    if (r)
    {
      string message = formatMessage("Sei sicuro di voler cancellare il riferimento a <b>|1</b>", r.Header1, ...)
      int answer = UIBusinessLogic.messageConfirmEx(message, "Sì;No")
       
      if (answer == 1)
      {
         r.delete()
      }
    }
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event WorkflowDiagramSubform.Load()
{
  this.hasCloseButton = false
  this.hasConfirmButton = false
  this.DiagramController = DiagramController.create(IDForm())
  Devextreme.DXCommunicator.addForm(this.IDForm())
  this.IsReadOnly = true
  this.UpdateFormButtons()
   
  WorkflowDiagramButtons.ButtonAddstep.clickEventType = Urgent
   
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event WorkflowDiagramSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  try 
  {
    MessageData md = cast(Doc)
    UIBusinessLogic.DTTLogMessage(formatMessage("Workflow Diagram message received: |1", Message, ...), 555, DTTInfo)
    UIBusinessLogic.DTTLogMessage(formatMessage("Workflow Diagram message body: |1", JSON.stringify(md.Content), ...), 555, DTTInfo)
  }
   
  switch (Message)
  {
    case onDiagramInitialized:
      // The DevExtreme widget reinitializes (page load / F5) with default readOnly=true.
      // Push current server-side state so the JS widget matches the session.
      Diagram.setReadOnlyMode(this.IsReadOnly)
    break
    case initJs:
      this.LoadMessage(Par1, Par2, Par3)
    break
    case load:
      this.handleLoadMessage(Message, Doc)
    break
    case exportJson:
      Diagram.exportJson()
    break
    case importJson:
      this.ImportJsonMessage(Doc)
    break
    case print:
      Diagram.printwkf()
    break
    case configuration:
      this.ConfigurationMessage(Doc)
    break
    case onStepDblClick:
      // FROM JS
      this.OnStepDblClickMessage(Doc)
    break
    case onFlowDblClick:
      // FROM JS
      this.OnFlowDblClickMessage(Doc)
    break
    case onInsertingStep:
      // FROM JS
      this.OnInsertingStepMessage(Doc)
    break
    case onUpdateStep:
      // FROM JS
      this.OnUpdateStepMessage(Doc)
    break
    case onDeleteStep:
      // FROM JS
      this.OnDeleteStepMessage(Doc)
    break
    case onInsertingFlow:
      // FROM JS
      this.OnInsertingFlowMessage(Doc)
    break
    case onFlowPointsChanged:
      // FORM JS
      this.onFlowPointsChange(Doc)
    break
    case onUpdateFlow:
      // FROM JS
      this.OnUpdateFlowMessage(Doc)
    break
    case onDeleteFlow:
      // FROM JS
      this.OnDeleteFlowMessage(Doc)
    break
    case readonly:
      Diagram.readOnly = if(Par1 == "-1", true, false)
    break
    case flowWithResultSelected:
      WkfFlow flowWithSelectedResult = cast(Doc)
      WKFFlowDetailForm.openFlowId(flowWithSelectedResult, this.DiagramHandler)
    break
    case updateDiagramStep:
      this.UpdateDiagramStepMessage(Doc)
    break
    case updateDiagramFlow:
      this.UpdateDiagramFlowMessage(Doc)
    break
    case deleteDiagramFlow:
      this.DeleteDiagramFlowMessage(Doc)
    break
    case onReadOnlyState:
      this.OnReadOnlyStateMessage(Doc)
    break
    case deleteDiagramStep:
      this.DeleteDiagramStepMessage(Doc)
    break
    case reloadDiagram:
      if (Evento.isMyInstance(Doc))
      {
         Evento currentEvento = cast(Doc)
         this.ReloadEventoDiagramMessage(currentEvento)
      }
      else 
      {
         this.ReloadModelloEventoDiagramMessage()
      }
    break
    case "UNLOCK_ADD_STEP_BTN":
      WorkflowDiagramButtons.ButtonAddstep.setEnabled(true)
    break
    default:
      UIBusinessLogic.DTTLogMessage(formatMessage("case '|1' not supported", Message, ...), ..., DTTWarning)
    break
  }
}


// ──────────────────────────────────

// **************************************************************************************
// Event raised to the form when it is activated, meaning when it is brought to the front
// **************************************************************************************
event WorkflowDiagramSubform.Activate()
{
  Diagram.isReadOnlyState()
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event WorkflowDiagramSubform.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  Diagram.close()
  Devextreme.DXCommunicator.removeForm(this.IDForm())
}


// ──────────────────────────────────

// **********
// export
// **********
event WorkflowDiagramSubform.Diagram.export(
  string Info // Info
)
{
  if (this.getParentForm())
  {
    DiagramContent dc = DiagramContent.create(Info)
    this.ParentForm.sendMessage(diagramContent, dc, ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe the purpose of this function...
// ****************************************
event WorkflowDiagramSubform.Diagram.onItemDblClick(
  IDMap Info // What is this parameter for?
)
{
  MessageData md = new()
  md.setObjectTag(data, Info)
  this.ParentForm.sendMessage(onStepDblClick, md, ...)
}


// ──────────────────────────────────

// ***********
// onItemClick
// ***********
event WorkflowDiagramSubform.Diagram.onItemClick(
  IDMap Info // Info
)
{
  MessageData md = new()
  md.setObjectTag(data, Info)
  this.ParentForm.sendMessage(onItemClick, md, ...)
}


// ──────────────────────────────────

// **********
// print
// **********
event WorkflowDiagramSubform.Diagram.print(
  string Info // Info
)
{
  MessageData md = new()
  md.setTag(data, Info)
  this.ParentForm.sendMessage(print, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe the purpose of this function...
// ****************************************
event WorkflowDiagramSubform.Diagram.OnSaveDiagram(
  string data // What is this parameter for?
)
{
  IDArray ida = new()
  ida.addValue(data)
  UIBusinessLogic.sendAppMessage("DIAGRAM_JSON", ida)
}


// ──────────────────────────────────

// ****************************************
// Describe the purpose of this function...
// ****************************************
event WorkflowDiagramSubform.Diagram.onInserting(
  IDMap value // What is this parameter for?
)
{
  MessageData md = new()
  md.setObjectTag(data, value)
  this.ParentForm.sendMessage(onInsertingStep, md, ...)
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe the purpose of this function...
// ****************************************
event WorkflowDiagramSubform.Diagram.onInsertingConnection(
  IDMap value // What is this parameter for?
)
{
  MessageData md = new()
  md.setObjectTag(data, value)
  this.ParentForm.sendMessage(onInsertingStep, md, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe the purpose of this function...
// ****************************************
event WorkflowDiagramSubform.Diagram.onDeleteConnection(
  IDMap key // What is this parameter for?
)
{
  MessageData md = new()
  md.setObjectTag(data, key)
  this.ParentForm.sendMessage(onDeleteFlow, md, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe the purpose of this function...
// ****************************************
event WorkflowDiagramSubform.Diagram.onConnectionDblClick(
  IDMap Info // What is this parameter for?
)
{
  MessageData md = new()
  md.setObjectTag(data, Info)
  this.ParentForm.sendMessage(onFlowDblClick, md, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe the purpose of this function...
// ****************************************
event WorkflowDiagramSubform.Diagram.onReadOnlyState(
  IDMap state // What is this parameter for?
)
{
  MessageData md = new()
  md.setObjectTag(data, state)
  this.ParentForm.sendMessage(onReadOnlyState, md, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe the purpose of this function...
// ****************************************
event WorkflowDiagramSubform.Diagram.onFlowPointsChanged(
  IDMap value // What is this parameter for?
)
{
  MessageData md = new()
  md.setObjectTag(data, value)
  this.ParentForm.sendMessage(onFlowPointsChanged, md, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe the purpose of this function...
// ****************************************
event WorkflowDiagramSubform.Diagram.onDiagramInitialized(
  string content // What is this parameter for?
)
{
  this.ParentForm.sendMessage(onDiagramInitialized, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WorkflowDiagramSubform.AddStep()
{
  Diagram d = this.DiagramHandler.GetDiagram()
  WkfStep step = d.createStepForDiagram("Step", ...)
  IDArray errArray = new()
   
  boolean stepHasBeenAdded = d.addStep(step, errArray)
   
  if (!(stepHasBeenAdded))
  {
    string stepErrors = d.GetStepErrors(step)
    stepErrors = stepErrors + Tools.ArrayToString(errArray, "<br/>")
    UIBusinessLogic.messageBox(stepErrors)
  }
  else 
  {
    Diagram.addStep(step.IDSTEP)
    WKFStepDetailForm.showForm(this)
    WKFStepDetailForm.loadStepData(this.DiagramHandler, step, true)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WorkflowDiagramSubform.AddStartStop()
{
  IDArray errors = new()
  Diagram d = this.DiagramHandler.GetDiagram()
  WkfStep wstart = d.getStartStep()
   
  if (wstart == null || wstart.IDSTEP <= 0)
  {
    wstart = WkfStep.create(d, "START", Start, Manuale, ...)
     
    if (!(d.addStep(wstart, errors)))
    {
      string errorMessage = d.GetStepErrors(wstart)
      errorMessage = errorMessage + Tools.ArrayToString(errors, "<br/>")
      UIBusinessLogic.messageBox(errorMessage)
      return 
    }
    else 
    {
      Diagram.addStart(wstart.IDSTEP)
    }
  }
  else 
  {
    WkfStep wstop = d.getStopStep()
    wstop = WkfStep.create(d, "STOP", Stop, Manuale, ...)
     
    if (!(d.addStep(wstop, errors)))
    {
      string errorMessage = d.GetStepErrors(wstop)
      errorMessage = errorMessage + Tools.ArrayToString(errors, "<br/>")
      UIBusinessLogic.messageBox(errorMessage)
      return 
    }
    else 
    {
      Diagram.addStop(wstop.IDSTEP)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WorkflowDiagramSubform.UnlockWorkflow()
{
  // toggle the flag
  this.IsReadOnly = !(this.IsReadOnly)
   
  Diagram.setReadOnlyMode(this.IsReadOnly)
   
  this.UpdateFormButtons()
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void WorkflowDiagramSubform.UpdateJsDiagram(
  ModelloEvento modelloEvento               // 
  optional Disposizione currentDisposizione // 
)
{
  string jsonShapes = modelloEvento.createJsonOfDiagramShapes(currentDisposizione)
  string jsonConnections = modelloEvento.createJsonOfDiagramFlows()
   
  // we don't use the shape toolbar anymore to add new shape so maybe we can remove Shape Configuration
  string shapeConfiguration = DiagramBackendInfo.GetJsonData(ShapeConfiguration)
   
  this.sendMessage(initJs, null, jsonShapes, jsonConnections, shapeConfiguration, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.LoadMessage(
  string Par1 // 
  string Par2 // 
  string Par3 // 
)
{
  Diagram.storedShape = Par1
  Diagram.storedConnection = Par2
  Diagram.storedShapeConfiguration = Par3
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.handleLoadMessage(
  string Message // 
  IDDocument Doc // 
)
{
  if (Message == "LOAD" and ModelloEvento.isMyInstance(Doc))
  {
    ModelloEvento me = (ModelloEvento)Doc
    if (me.IDTEMPLATEEVENTO > 0)
    {
      this.ModelloEvento = me
      Diagram d = me.GetDiagram()
      this.handleVisibilityOfMigrateFromXmlButton(me)
      this.DiagramHandler = this.DiagramHandler.create(d, this)
    }
  }
   
  if (Evento.isMyInstance(Doc))
  {
    WorkflowDiagramButtons.visible = false
     
    Evento e = (Evento)Doc
    if (e.IDTEMPLATEEVENTO > 0)
    {
      ModelloEvento me = e.getModelloEvento()
       
      if (me != null and me.isWorkflowModelloEvento())
      {
         this.ModelloEvento = me
         Diagram d = me.GetDiagram()
         if (d != null)
         {
           this.DiagramHandler = this.DiagramHandler.create(d, this)
         }
      }
    }
    e.updated = false
  }
   
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.ConfigurationMessage(
  IDDocument Doc // 
)
{
  DiagramConfiguration dc = (DiagramConfiguration)Doc
  this.DiagramController.setConfiguration(dc)
  Diagram.configuration = this.DiagramController.getConfigurationToJson()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.OnStepDblClickMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  this.DiagramHandler.setMessageData(md)
  Diagram d = this.DiagramHandler.GetDiagram()
   
  int stepId = md.Content.getValue("key")
   
  if (stepId > 0)
  {
     
    WkfStep step = d.getStepFromDiagram(stepId)
     
    if (step == null || step.IDSTEP < 0)
    {
       
      UIBusinessLogic.messageBox("Something went wrong... step not found in Diagram")
      return 
    }
     
    if (lower(step.STEPDESCRIPTION) != "start" and lower(step.STEPDESCRIPTION) != "stop")
    {
      WKFStepDetailForm.showForm(this)
      WKFStepDetailForm.loadStepData(this.DiagramHandler, step, ...)
    }
  }
  else 
  {
    UIBusinessLogic.messageBox("Step ID is 0")
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.OnFlowDblClickMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  this.DiagramHandler.setMessageData(md)
   
  int flowId = md.Content.getValue("key")
  if (flowId > 0)
  {
    WKFFlowDetailForm.show(Modal)
    Diagram d = this.DiagramHandler.GetDiagram()
    WkfFlow wf = d.getFlowFromDiagram(flowId)
    WKFFlowDetailForm.openFlowId(wf, this.DiagramHandler)
  }
  else 
  {
    UIBusinessLogic.messageBox("Flow ID is 0")
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.onFlowPointsChange(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  this.DiagramHandler.setMessageData(md)
  Diagram d = this.DiagramHandler.GetDiagram()
   
  WkfFlow flowToBeChange = d.getFlowFromDiagram(md.Content.getValue("connectorId"))
  if (flowToBeChange != null && flowToBeChange.IDFLOW > 0)
  {
    flowToBeChange.POINTS = md.Content.getValue("points")
     
  }
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.OnInsertingStepMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  this.DiagramHandler.setMessageData(md)
  Diagram d = this.DiagramHandler.GetDiagram()
   
  WkfStep step = d.createStepForDiagram("", Step, ...)
  IDArray errorsArray = new()
  this.AddStep()
   
  if (errorsArray.length() > 0)
  {
    string errorsString = Tools.ArrayToString(errorsArray, ...)
    UIBusinessLogic.messageBox(errorsString)
  }
  else 
  {
    WKFStepDetailForm.showForm(this)
    WKFStepDetailForm.loadStepData(this.DiagramHandler, step, ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.OnUpdateStepMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
   
  UIBusinessLogic.DTTLogMessage("onUpdateStep: " + JSON.stringify(md.Content), ...)
   
  IDMap messaggio = md.Content
  int idStep = toInteger(messaggio.getValue("id"))
   
  if (idStep > 0)
  {
    Diagram d = this.DiagramHandler.GetDiagram()
     
    // weird.. somethimes is null..
    if (d == null)
      return 
     
    IDCollection steps of WkfStep = d.GetSteps()
    for each WkfStep ws in steps
    {
      if (ws.IDSTEP == idStep)
      {
         ws.X = toFloat(messaggio.getValue("x"))
         ws.Y = toFloat(messaggio.getValue("y"))
         ws.HEIGHT = toFloat(messaggio.getValue("height"))
         ws.WIDTH = toFloat(messaggio.getValue("width"))
      }
    }
  }
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.OnDeleteStepMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  this.DiagramHandler.setMessageData(md)
  Diagram d = this.DiagramHandler.GetDiagram()
   
  WkfStep ws = d.getStepFromDiagram(md.Content.getValue("id"))
   
  if (ws == null)
  {
    UIBusinessLogic.DTTLogMessage("Can't get the step to delete from Diagram: " + md.Content.getValue("id"), ..., DTTError)
    UIBusinessLogic.messageBox("Errore interno")
    return 
  }
   
  // this shitty thing because get flow of specific step return a reference to step, but when I delete the step the flows will be deleted too
  IDCollection flowsToDelete of WkfFlow = d.getFlowsOfSpecificStep(ws)
  UIBusinessLogic.DTTLogMessage("Flow to delete collection " + toString(flowsToDelete.count()), 666, ...)
   
  // store the IDFlow to be deleted in an aray to use it below and to avoid to handle deleted objects
  IDArray deleteFlowsIds = new()
  for each WkfFlow wf in flowsToDelete
  {
    deleteFlowsIds.addValue(wf.IDFLOW)
  }
   
  IDArray errorsArray = new()
   
  boolean isStepDeleted = d.removeStep(ws, errorsArray)
  if (!(isStepDeleted))
  {
    string errorMessage = Tools.ArrayToString(errorsArray, "<br/>")
    UIBusinessLogic.messageBox("Step non eliminato. <br/>" + errorMessage)
  }
  else 
  {
    // delete flows in js (wwe use the array becaue it is the solidiest approach foun)
    for (int i = 0; i < deleteFlowsIds.length(); i = i + 1)
    {
      int idFlowToBeDeleted = deleteFlowsIds.getValue(i)
      Diagram.deleteFlow(toString(idFlowToBeDeleted))
    }
  }
   
//  UIBusinessLogic.messageBox("Shape Deleted: " + toString(md.Content.getValue("key")))
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.OnInsertingFlowMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  this.DiagramHandler.setMessageData(md)
  Diagram diagram = this.DiagramHandler.GetDiagram()
   
  string originalFlowKey = md.Content.getValue("id")
  WkfStep fromStep = diagram.getStepFromDiagram(md.Content.getValue("fromId"))
  WkfStep toStep = diagram.getStepFromDiagram(md.Content.getValue("toId"))
  if (fromStep != null && toStep != null)
  {
    UIBusinessLogic.DTTLogMessage(formatMessage("From Step |1 - To Step |2", fromStep.IDSTEP, toStep.IDSTEP, ...), 999999, ...)
  }
  if (fromStep == null or toStep == null)
  {
    if (fromStep == null)
    {
      string messageContent = ""
      if (md)
         messageContent = md.saveToXML(false, null, 0, JSON, ...)
      UIBusinessLogic.DTTLogMessage(formatMessage("No valid from step from message: '|1'", messageContent, ...), ..., DTTError)
    }
     
    // delete just created flow line
    this.sendMessage(deleteDiagramFlow, Doc, ...)
    return 
  }
   
  IDCollection freeResults of WkfResult = diagram.getNonAssignedResultsOfStep(fromStep, ...)
  UIBusinessLogic.DTTLogMessage(freeResults.saveToXML(false, null, 0, JSON, ...), 999999, ...)
//  freeResults.saveToXML(false, null, 0, JSON, ...)
  if (freeResults == null)
  {
    UIBusinessLogic.DTTLogMessage("No valid free result", ..., DTTError)
    return 
  }
  if (freeResults.count() == 0 and fromStep.BLOCKTYPE != Start)
  {
    UIBusinessLogic.messageBox("Non ci sono esiti disponibili per questo Step, la connessione non può essere aggiunta.")
     
    // delete just created flow line
    this.sendMessage(deleteDiagramFlow, Doc, ...)
  }
  else 
  {
    IDArray errorsArray = new()
    if (fromStep != null and toStep != null)
    {
      WkfFlow flow = WkfFlow.create(this.ModelloEvento, fromStep, toStep, ...)
      flow.TOPOINTINTEX = toInteger(md.Content.getValue("toPointIndex"))
      flow.FROMPOINTINTEX = toInteger(md.Content.getValue("fromPointIndex"))
      flow.POINTS = md.Content.getValue("points")
      boolean validFlow = diagram.ValidateFlow(fromStep, toStep, errorsArray, flow, true)
      if ((validFlow and freeResults.count() > 0) or (validFlow and fromStep.isStartStep()))
      {
         diagram.AddFlowToCollection(flow)
          
         WKFFlowDetailForm.openFlowId(flow, this.DiagramHandler)
          
         // change the flow id on JS diagram to allign with inde
         Diagram.changeFlowId(originalFlowKey, flow.IDFLOW)
      }
      else 
      {
         // delete just created flow and remove form DGFlow collection
          
         diagram.removeFlow(flow, errorsArray)
         Diagram.deleteFlow(originalFlowKey)
         string errorString = Tools.ArrayToString(errorsArray, "<br>")
         UIBusinessLogic.messageBox(errorString)
      }
    }
  }
   
   
//  UIBusinessLogic.messageBox(toString(md.Content.getValue("id")) + " connected from " + toString(md.Content.getValue("fromId")) + "shape to " + toString(md.Content.getValue("toId")) + " shape")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.OnUpdateFlowMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  this.DiagramHandler.setMessageData(md)
  Diagram d = this.DiagramHandler.GetDiagram()
   
  IDArray errors = new()
   
  WkfStep fromStep = d.getStepFromDiagram(md.Content.getValue("fromId"))
  WkfStep toStep = d.getStepFromDiagram(md.Content.getValue("toId"))
  WkfFlow wf = d.getFlowFromDiagram(md.Content.getValue("id"))
  boolean openFlowForm = true
   
  if (wf != null && wf.IDFLOW > 0)
  {
     
    int newFromPointIndex = toInteger(md.Content.getValue("fromPointIndex"))
    int newToPointIndex = toInteger(md.Content.getValue("toPointIndex"))
    int newIdStep = toInteger(md.Content.getValue("fromId"))
    int newIdNextStep = toInteger(md.Content.getValue("toId"))
     
    if (newFromPointIndex == wf.FROMPOINTINTEX and newToPointIndex == wf.TOPOINTINTEX and newIdStep == wf.IDSTEP and newIdNextStep == wf.IDNEXTSTEP)
    {
      openFlowForm = false
    }
     
    wf.FROMPOINTINTEX = toInteger(md.Content.getValue("fromPointIndex"))
    wf.TOPOINTINTEX = toInteger(md.Content.getValue("toPointIndex"))
    wf.IDSTEP = toInteger(md.Content.getValue("fromId"))
    wf.IDNEXTSTEP = toInteger(md.Content.getValue("toId"))
    wf.POINTS = md.Content.getValue("points")
  }
   
   
  string originalFlowKey = md.Content.getValue("id")
   
  // beccare il caso in cui collego un flow che prima era scollegato, quindi senza un id valido e devo aprire la modale
  if (fromStep != null && toStep != null)
  {
    if (wf == null)
    {
      wf = WkfFlow.create(this.ModelloEvento, fromStep, toStep, ...)
      d.AddFlowToCollection(wf)
    }
     
    boolean validFlow = d.ValidateFlow(fromStep, toStep, errors, wf, false)
     
    if (validFlow)
    {
      if (openFlowForm == true)
      {
         WKFFlowDetailForm.openFlowId(wf, this.DiagramHandler)
      }
       
      // change the flow id on JS diagram to allign with inde
      Diagram.changeFlowId(originalFlowKey, wf.IDFLOW)
    }
    else 
    {
      // delete just created flow and remove form DGFlow collection
      d.removeFlow(wf, errors)
      Diagram.deleteFlow(originalFlowKey)
      string errorString = Tools.ArrayToString(errors, "<br>")
      UIBusinessLogic.messageBox(errorString)
    }
    return 
  }
   
  // oltre a questo beccare caso in cui scollego un flow
  if (wf != null && (fromStep == null || toStep == null))
  {
    Diagram.deleteFlow(toString(wf.IDFLOW))
    d.removeFlow(wf, errors)
  }
   
  if (errors.length() > 0)
  {
    UIBusinessLogic.messageBox(Tools.ArrayToString(errors, "<br/>"))
  }
//  UIBusinessLogic.messageBox("Connection updated: " + toString(md.Content.getValue("id")))
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.UpdateDiagramStepMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  UIBusinessLogic.DTTLogMessage(formatMessage("MessageData.Content: |1", formatMessage(JSON.stringify(md.Content), ...), ...), ...)
   
  Diagram.updateStep(md.Content.getValue("id"), md.Content.getValue("description"), md.Content.getValue("text"))
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.UpdateDiagramFlowMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  UIBusinessLogic.DTTLogMessage(formatMessage("MessageData.Content: |1", formatMessage(JSON.stringify(md.Content), ...), ...), ...)
   
  Diagram.updateFlow(md.Content.getValue("id"), md.Content.getValue("text"))
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.DeleteDiagramFlowMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  UIBusinessLogic.DTTLogMessage(formatMessage("MessageData.Content: |1", formatMessage(JSON.stringify(md.Content), ...), ...), ...)
   
  // deleteflow
  Diagram.deleteFlow(md.Content.getValue("id"))
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.OnReadOnlyStateMessage(
  IDDocument Doc // 
)
{
  MessageData md = cast(Doc)
  boolean b = md.Content.getValue("state")
  this.IsReadOnly = b
  Diagram.setReadOnlyMode(b)
  UIBusinessLogic.DTTLogMessage("Is diagram true false? " + toString(md.Content.getValue("state")), ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.DeleteDiagramStepMessage(
  IDDocument Doc // Write a comment for this parameter or press backspace to delete this comment
)
{
  MessageData md = cast(Doc)
  this.MessageData = md
  UIBusinessLogic.DTTLogMessage(formatMessage("MessageData.Content: |1", formatMessage(JSON.stringify(md.Content), ...), ...), ...)
   
  // deleteflow
  Diagram.deleteStep(md.Content.getValue("id"))
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
private void WorkflowDiagramSubform.ReloadEventoDiagramMessage(
  Evento currentEvento // 
)
{
  if (currentEvento != null)
  {
    Disposizione currentDisposizione = currentEvento.getNonClosedWorkflowDisposizione()
    this.UpdateJsDiagram(this.ModelloEvento, currentDisposizione)
    //  
    // Diagram.impostaComeColoratoLoStep(idStep)
    string jsonShapes = this.ModelloEvento.createJsonOfDiagramShapes(currentDisposizione)
    string jsonFlows = this.ModelloEvento.createJsonOfDiagramFlows()
    Diagram.updateCollections(jsonShapes, jsonFlows)
  }
   
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
private void WorkflowDiagramSubform.ReloadModelloEventoDiagramMessage()
{
  this.UpdateJsDiagram(this.ModelloEvento, ...)
  string jsonShapes = this.ModelloEvento.createJsonOfDiagramShapes(...)
  string jsonFlows = this.ModelloEvento.createJsonOfDiagramFlows()
  Diagram.updateCollections(jsonShapes, jsonFlows)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WorkflowDiagramSubform.UpdateFormButtons()
{
  WorkflowDiagramButtons.ButtonaddStartStop.setEnabled(!(this.IsReadOnly))
  WorkflowDiagramButtons.ButtonAddstep.setEnabled(!(this.IsReadOnly))
  WorkflowDiagramButtons.ButtonLockUnlock.setEnabled(true)
   
  if (this.IsReadOnly == true)
  {
    WorkflowDiagramButtons.ButtonLockUnlock.caption = "{{icon-fa-lock}}"
  }
  else 
  {
    WorkflowDiagramButtons.ButtonLockUnlock.caption = "{{icon-fa-lock-open}}"
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WorkflowDiagramSubform.MigrateFromXml()
{
  this.ModelloEvento.migrateDiagramFromXml()
   
  this.sendMessage(reloadDiagram, ...)
   
  this.handleVisibilityOfMigrateFromXmlButton(this.ModelloEvento)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void WorkflowDiagramSubform.handleVisibilityOfMigrateFromXmlButton(
  ModelloEvento me // 
)
{
  if (me.CUSTOMEXPORTEDDIAGRAMXML != "")
  {
    WorkflowDiagramButtons.MigrateFromXml.setVisible(true)
  }
  else 
  {
    WorkflowDiagramButtons.MigrateFromXml.setVisible(false)
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DocCollegatiSubform.Load()
{
  IDPanel idp = DocCollegato.IDPanel()
  PanelRowButtonController prbc = PanelRowButtonController.create(idp, this)
  prbc.setup(left, ask, right, DocCollegatiCommandSetforRow.IDCommand())
   
  DocCollegato.caption = ""
  DocCollegato.collapsable = false
  DocCollegatoQuickview.collapsable = false
   
  DocCollegatoQuickview.visible = false
   
  Aggiungi.clickEventType = Urgent
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event DocCollegatiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "LOAD":
      MainModule mm = (MainModule)Doc
      this.MainModule = mm
      if (mm)
      {
         if (mm.DocCollegati.count() == 0)
         {
           mm.loadDocCollegati()
         }
         DocCollegato.setCollection(mm.DocCollegati, true)
         this.setFieldsVisibilityForModelloEventi()
         this.quickView()
      }
    break
    case "setLookupResults":
      SearchResult sr = (SearchResult)Doc
      this.addSelectedDocumentsInPanel(sr)
    break
    case "RevisionSelected":
      Revision r = (Revision)Doc
      DocCollegato dc = DocCollegato.document
      if (dc)
      {
         dc.blockRevision(r)
      }
    break
    case "DELETE_ROW":
      if (!(this.MainModule.isLocked()))
      {
         this.Delete()
      }
    break
    case LOCK_PANELS:
      DocCollegato.locked = true
      DocCollegatoQuickview.locked = true
      ModelloEvento.locked = true
      Aggiungi.visible = false
    break
    case UNLOCK_PANELS:
      DocCollegato.locked = false
      DocCollegatoQuickview.locked = false
      ModelloEvento.locked = false
      Aggiungi.visible = true
    break
  }
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event DocCollegatiSubform.DocCollegato.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  if (Button == Left or Button == Right)
  {
    if (Row != -1 and DocCollegato.document != null)
    {
      this.quickView()
      this.setCommandSetVisiblity()
    }
    else 
    {
      this.CloseDocCollegatoQuickView()
    }
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event DocCollegatiSubform.DocCollegato.OnDynamicProperties()
{
  if (DocCollegato.NroRevisioneToBeDisplayed == 0)
    DocCollegato.nroRevisioneString.text = "00"
  else 
    DocCollegato.nroRevisioneString.text = toString(DocCollegato.NroRevisioneToBeDisplayed)
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event DocCollegatiSubform.DocCollegatoQuickview.OnDynamicProperties()
{
  DocCollegato dc = DocCollegatoQuickview.document
   
  if (dc)
  {
    if (dc.NroRevisioneToBeDisplayed == 0)
      DocCollegatoQuickview.nroRevisioneString.text = "00"
    else 
      DocCollegatoQuickview.nroRevisioneString.text = toString(dc.NroRevisioneToBeDisplayed)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.quickView()
{
  DocCollegato dc = DocCollegato.document
  if (dc)
  {
    DocCollegatoQuickview.setDocument(dc, true)
    DocCollegatoQuickview.visible = true
  }
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.setFieldsVisibilityForModelloEventi()
{
  int:kordapp kordapp = this.MainModule.getKordApp()
  if (kordapp == ModelliEventi)
  {
    ModelloEvento me = (ModelloEvento)this.MainModule
    ModelloEvento.visible = true
    ModelloEvento.setDocument(me, true)
    DocCollegato.LockedRevisione.setVisible(false)
     
    // changed from set visible to set enable because if not visible there is a white space in the form
    DocCollegatoQuickview.LockedRevisione.setEnabled(false)
     
    Bloccarevisione.visible = false
    Nonbloccarerevisione.visible = false
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.Bloccarevisione()
{
  DocCollegato dc = DocCollegato.document
  if (dc)
  {
    IDCollection approvedRevisions of Revision = dc.Documento.getApprovedRevisions()
    if (approvedRevisions.count() == 1)
    {
      approvedRevisions.moveFirst()
      Revision r = (Revision)approvedRevisions.getAt()
      dc.blockRevision(r)
    }
    else 
    {
      DocRevisioneSelection.showForm(this, approvedRevisions)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.Nonbloccarerevisione()
{
  DocCollegato dc = DocCollegato.document
  if (dc)
  {
    dc.unblockRevision()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.Aggiungi()
{
  LookupHelper lh = LookupHelper.create(this.IDForm(), Documenti, true, ...)
  lh.displayLookup()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.Delete()
{
  DocCollegato dc = DocCollegato.document
  if (dc)
  {
    dc.delete()
     
    // following code clear the Text of Vertical Panel in case of all documents are deleted and no any document exists
    IDCollection docCollegati of DocCollegato = DocCollegato.collection
    if (docCollegati.count() == 0)
    {
      DocCollegato docCollegato = new()
      DocCollegatoQuickview.setDocument(docCollegato, true)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.addSelectedDocumentsInPanel(
  SearchResult searchResult // 
)
{
  int:kordapp kordapp = this.MainModule.getKordApp()
  int mainId = this.MainModule.getMainID()
  IDCollection selectedIdsInSearch of IntDataType = searchResult.getDataTypeCollection()
  for each IntDataType idt in selectedIdsInSearch
  {
    DocCollegato dc = DocCollegato.create(kordapp, mainId, idt.IntegerValue, ...)
    MainModule.DocCollegati.add(dc)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.setCommandSetVisiblity()
{
  if (this.MainModule)
  {
    int:kordapp kordapp = this.MainModule.getKordApp()
    if (kordapp != ModelliEventi)
    {
      DocCollegato dc = DocCollegato.document
      if (dc)
      {
         DocCollegatiCommandSetforRow.setCommandVisible(Bloccarevisione.getIndex(), !(dc.LockedRevisione))
         DocCollegatiCommandSetforRow.setCommandVisible(Nonbloccarerevisione.getIndex(), dc.LockedRevisione)
      }
       
    }
    if (this.MainModule.isLocked())
    {
      DocCollegatiCommandSetforRow.setCommandVisible(Bloccarevisione.getIndex(), false)
      DocCollegatiCommandSetforRow.setCommandVisible(Nonbloccarerevisione.getIndex(), false)
      DocCollegatiCommandSetforRow.setCommandVisible(Open.getIndex(), false)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.Open()
{
  DocCollegato dc = DocCollegato.document
  if (dc)
  {
    if (dc.Documento)
    {
      OnlyOfficeDocumentOpener.open(dc.Documento, this, view)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocCollegatiSubform.CloseDocCollegatoQuickView()
{
  DocCollegatoQuickview.visible = false
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event DocRevisioneSelection.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  Revision r = Revision.document
   
  this.Caller.sendMessage("RevisionSelected", r, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DocRevisioneSelection.showForm(
  IDForm callerForm                          // 
  IDCollection approvedRevisions of Revision // Write a comment for this parameter or press backspace to delete this comment
)
{
  this.Caller = callerForm
  Revision.setCollection(approvedRevisions, true)
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event DocumentiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "LOAD" or Message == LOCK_PANELS or Message == UNLOCK_PANELS)
  {
    DocComunicazioniSubform.sendMessage(Message, Doc, Par1, Par2, Par3, Par4)
    DocCollegatiSubform.sendMessage(Message, Doc, Par1, Par2, Par3, Par4)
  }
}


// ──────────────────────────────────

// ********************************************************************
// Hides the Doc Comunicazioni page from the internal tabbed view.
// Called by ModelloEventoUILogic.afterSubformCreation so that on
// ModelloEvento, only the Doc Collegati page is visible. The outer tab
// caption for this scenario is already set to "Doc Collegati" at the
// TabDefinition level.
// ********************************************************************
public void DocumentiSubform.enterModelloEventoMode()
{
  this.caption = "{{icon-fa-paperclip}} Doc Collegati"
   
  int pageIndex = DocTabbedView.getFormPageIndex(DocComunicazioniSubform.IDForm())
  if (pageIndex >= 0)
  {
    DocTabbedView.deleteForm(DocComunicazioniSubform.IDForm())
    DocTabbedView.hiddenTabs = true
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event ModelliAndEventiCostiSubform.Load()
{
  CostiList.collapsable = false
  CostiList.collapsed = false
  CostiList.caption = ""
  CostiList.setCommandEnabled(Duplicate, false)
  CostiList.setCommandEnabled(Refresh, false)
  CostiList.setCommandEnabled(Insert, false)
  CostiList.setCommandEnabled(Delete, false)
   
  newCosto.clickEventType = Urgent
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event ModelliAndEventiCostiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "LOAD":
      this.handleLoadMessage(Doc)
    break
    case "SAVE":
      this.handleSaveMessage(Doc)
    break
    case LOCK_PANELS:
      CostiList.locked = true
      modelloeventocostiquickviewpanel.locked = true
      eventicostiquickviewpanel.locked = true
      newCosto.visible = false
      CostiList.Cancella.setEnabled(false)
    break
    case UNLOCK_PANELS:
      CostiList.locked = false
      modelloeventocostiquickviewpanel.locked = false
      eventicostiquickviewpanel.locked = false
      newCosto.visible = true
      CostiList.Cancella.setEnabled(true)
    break
    case "setLookupResults":
      if (Par1 != "")
      {
         EventiCosto ec = eventicostiquickviewpanel.document
         ec.IDARTICOLO = toInteger(Par1)
         ec.ArticoloDescrForUI = Par2
         Articolo a = Articolo.getFromDB(ec.IDARTICOLO, quickLoad)
         ec.CODUM = a.CODUMVENDITA
         ec.PREZZO = a.PZZOACQUISTO
      }
    break
  }
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event ModelliAndEventiCostiSubform.CostiList.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  if (Row > -1)
  {
    EventiCosto ec = CostiList.document
    if (ec)
    {
      this.openQuickview(ec)
    }
    if (Button == Right)
    {
      CostiCommandMenu.openPopupXY(XB, YB)
    }
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelliAndEventiCostiSubform.newCosto()
{
  switch (this.DisplayMode)
  {
    case ModelloEventoCostiMode:
      if (this.ModelloEvento != null)
      {
         EventiCosto eventoCosto = EventiCosto.create(null, this.ModelloEvento)
         IDCollection coll of EventiCosto = CostiList.collection
         coll.add(eventoCosto)
         this.openQuickview(eventoCosto)
         CostiList.findDocument(eventoCosto)
      }
    break
    case EventoCostiMode:
      if (this.Evento != null)
      {
         EventiCosto eventoCosto = EventiCosto.create(this.Evento, null)
         IDCollection coll of EventiCosto = CostiList.collection
         coll.add(eventoCosto)
         this.openQuickview(eventoCosto)
         CostiList.findDocument(eventoCosto)
      }
    break
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelliAndEventiCostiSubform.deleteCosto()
{
  EventiCosto eventoCosto = CostiList.document
  eventoCosto.deleted = true
  this.closemodelloeventoquickview()
  this.closeeventoquickview()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelliAndEventiCostiSubform.openQuickview(
  EventiCosto costo // 
)
{
  switch (this.DisplayMode)
  {
    case ModelloEventoCostiMode:
      eventicostiquickviewpanel.visible = false
       
      modelloeventocostiquickviewpanel.visible = true
      modelloeventocostiquickviewpanel.setDocument(costo, true)
    break
    case EventoCostiMode:
      modelloeventocostiquickviewpanel.visible = false
       
      eventicostiquickviewpanel.visible = true
      eventicostiquickviewpanel.setDocument(costo, true)
    break
  }
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelliAndEventiCostiSubform.closemodelloeventoquickview()
{
  modelloeventocostiquickviewpanel.visible = false
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelliAndEventiCostiSubform.closeeventoquickview()
{
  eventicostiquickviewpanel.visible = false
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelliAndEventiCostiSubform.ArticoloDescrForUI()
{
  LookupHelper lh = LookupHelper.create(this, Articoli, false, ...)
  lh.displayLookup()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelliAndEventiCostiSubform.handleSaveMessage(
  IDDocument Doc // 
)
{
  EventiCosto passedEventoCosto = (EventiCosto)Doc
  IDCollection eventiCosti of EventiCosto = CostiList.collection
   
  EventiCosto eventoCostoFound = null
   
  eventiCosti.add(passedEventoCosto)
  for each EventiCosto ec in eventiCosti
  {
    if (ec.IDCOSTO == passedEventoCosto.IDCOSTO)
    {
      eventoCostoFound = ec
      break 
    }
  }
  if (eventoCostoFound == null)
  {
    eventiCosti.add(passedEventoCosto)
  }
  else 
  {
    eventoCostoFound = passedEventoCosto
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelliAndEventiCostiSubform.handleLoadMessage(
  IDDocument Doc // 
)
{
  if (ModelloEvento.isMyInstance(Doc))
  {
    ModelloEvento me = (ModelloEvento)Doc
    this.ModelloEvento = me
    this.DisplayMode = ModelloEventoCostiMode
    if (me.Costi.count() == 0)
    {
      me.loadModelloEventoCosts(true)
    }
     
    CostiList.DATA.setVisible(false)
     
    CostiList.setCollection(me.Costi, true)
  }
   
  if (Evento.isMyInstance(Doc))
  {
    Evento e = (Evento)Doc
    this.Evento = e
    this.DisplayMode = EventoCostiMode
    if (e.EventiCosti.count() == 0)
    {
      e.loadEventoCosti(true)
    }
     
    CostiList.DATA.setVisible(true)
     
    CostiList.setCollection(e.EventiCosti, true)
  }
   
  modelloeventocostiquickviewpanel.visible = false
  eventicostiquickviewpanel.visible = false
   
  modelloeventocostiquickviewpanel.collapsed = false
  modelloeventocostiquickviewpanel.collapsable = false
  eventicostiquickviewpanel.collapsed = false
  eventicostiquickviewpanel.collapsable = false
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void CliforDetailSubform.showPicture(
  optional string forcedExtension = "" // 
)
{
  Clifor c = Cliforinfo.document
  if (c and c.FOTO != null)
  {
    string filename = docIDToGuid(newDocID())
     
    string FOTOextension = ""
    if (forcedExtension != "")
      FOTOextension = forcedExtension
    else 
      FOTOextension = c.ExtractImageFieldFileExtension(...)
     
    string filenameWithExtension = formatMessage("|1.|2", filename, FOTOextension, ...)
     
    string FOTOPath = saveBlobFile(c.FOTO, UIBusinessLogic.path() + FH.getSeparator() + "images", filenameWithExtension)
     
    Cliforinfo.Foto.loadImage(filenameWithExtension)
     
    UIBusinessLogic.addTempFile(FOTOPath)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void CliforDetailSubform.handleLoadMessage(
  IDDocument Doc // 
)
{
  if (X.inServerSession())
  {
    UIBusinessLogic.DTTLogMessage("in server session likely we are in IdUnit so we return to avoid panel errors", ..., DTTInfo)
    return 
  }
   
  Clifor c = (Clifor)Doc
  Cliforinfo.setDocument(c, ...)
  caratterizzazioniPanel.setCollection(c.GCFCARATTERIZZAZIONI, true)
   
  this.showPicture(...)
   
  int noteHtmlPropertyIndex = c.getPropertyIndex("NOTEHTML", true, true, true, true)
  HTMLEditorConfiguration htmlec = HTMLEditorConfiguration.create(500, c, noteHtmlPropertyIndex, false)
  IDForm htmlEditorSubform = getDevextremeSubformInstance(html)
  Cliforinfo.NoteHtml.setLabelSubForm(htmlEditorSubform, ...)
  htmlEditorSubform.sendMessage(configuration, htmlec, ...)
  c.updated = false
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void CliforDetailSubform.modifyComune()
{
  Clifor c = Cliforinfo.document
  if (c and c.IDCONTO > 0)
  {
    int comuneIndex = c.getPropertyIndex("COMUNE", true, true, true, true)
    int capIndex = c.getPropertyIndex("CAP", true, true, true, true)
    int provinciaIndex = c.getPropertyIndex("CODPROVINCIA", true, true, true, true)
    int statoIndex = c.getPropertyIndex("CODSTATO", true, true, true, true)
    ComuniSelection.showForm(c.COMUNE, c, comuneIndex, capIndex, provinciaIndex, statoIndex)
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event CliforDetailSubform.Load()
{
  Cliforinfo.collapsable = false
  caratterizzazioniPanel.collapsable = false
  caratterizzazioniPanel.layout = List
  caratterizzazioniPanel.setCommandEnabled(Update, false)
  caratterizzazioniPanel.setCommandEnabled(Duplicate, false)
  caratterizzazioniPanel.setCommandEnabled(Cancel, false)
   
  Cliforinfo.setErrorMode(Message, Message, Message, Message)
   
  LookupBuilder vlb = LookupBuilder.create(Cliforinfo.IDPanel())
  Stati s = new()
  vlb.computeValueList(Cliforinfo.CODSTATO.me(), s, "CODSTATO", "DESCRSTATO", ...)
   
  Cliforinfo.Foto.setBlobSize(10000000, 10000000, false)
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event CliforDetailSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message = "LOAD")
  {
    this.handleLoadMessage(Doc)
  }
}


// ──────────────────────────────────

// **************************************************************************************************************************
// Event raised by the panel after saving the file uploaded by the user to the database or deleting the contents of the blob.
// **************************************************************************************************************************
event CliforDetailSubform.Cliforinfo.AfterBLOBUpdate(
  int Column       // An integer specifying which panel field is involved in the update or delete operation. It should be compared with the Me function of the panel fields.
  int Size         // Size of the uploaded file in bytes, or -1 if the contents of the blob have been deleted.
  string Extension // A string containing the extension of the file being loaded.
)
{
  this.showPicture(Extension)
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event CliforDetailSubform.Cliforinfo.OnDynamicProperties()
{
  string titleClifor = "<span class="firstRow-title">" + Cliforinfo.RAGIONESOCIALE + "</span>"
  string infoClifor = "<span class="firstRow-info">" + Cliforinfo.CODCONTO + " · " + Cliforinfo.DESCRTIPOCONTOClifor.text + "</span>"
   
  Cliforinfo.LabelLabelTitoloClifor.caption = titleClifor + "<br>" + infoClifor
   
  string valueListStatoConto = ""
  switch (Cliforinfo.STATOCONTO)
  {
    case "A":
      valueListStatoConto = "Attivo"
    break
    case "C":
      valueListStatoConto = "Chiuso"
    break
    case "P":
      valueListStatoConto = "Potenziale"
    break
  }
  string statoClifor = "<span class="stato-" + lower(valueListStatoConto) + "">" + valueListStatoConto + "</span>"
   
  Cliforinfo.LabelLabelStatoClifor.caption = statoClifor
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event CliforDetailSubform.caratterizzazioniPanel.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    IDCollection coll of GCFCARATTERIZZAZIONI = caratterizzazioniPanel.collection
    GCFCARATTERIZZAZIONI newTag = GCFCARATTERIZZAZIONI.create(Cliforinfo.IDCONTO)
    coll.add(newTag)
  }
   
}


// ──────────────────────────────────



// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event AddressesSubform.Load()
{
  Addresses.caption = ""
  Addresses.setCommandEnabled(Update, false)
  Addresses.setCommandEnabled(Refresh, false)
  Addresses.setCommandEnabled(Insert, false)
  Addresses.setCommandEnabled(Delete, false)
  Addresses.setCommandEnabled(Search, false)
  Addresses.setCommandEnabled(Duplicate, false)
   
  Addresses.collapsable = false
  Addresses.listQBE = No
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AddressesSubform.Add()
{
  IDCollection addresses of IndirizzoClifor = Addresses.collection
  IndirizzoClifor ic = IndirizzoClifor.create(this.Clifor)
  addresses.add(ic)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AddressesSubform.Delete()
{
  Addresses.deleteRow()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void AddressesSubform.handleLoadMessage()
{
  if (this.Clifor and this.Clifor.IDCONTO > 0)
  {
    this.Clifor.loadCliforAddresses(...)
    Addresses.setCollection(this.Clifor.Addresses, true)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ComuniSelection.showForm(
  string actualValue                       // Write a comment for this parameter or press backspace to delete this comment
  IDDocument module                        // 
  optional int comuneIndexField = -1       // 
  optional int capIndexField = -1          // 
  optional int codProvinciaIndexField = -1 // 
  optional int codStatoIndexField = -1     // 
)
{
  this.LoadData()
  this.PreviousSelection = actualValue
  this.Module = module
  IDMap propIndexes = new()
  propIndexes.setValue("comune", comuneIndexField)
  propIndexes.setValue("cap", capIndexField)
  propIndexes.setValue("codprovincia", codProvinciaIndexField)
  propIndexes.setValue("codstato", codStatoIndexField)
  this.PropertiesToBeSet = propIndexes
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ComuniSelection.LoadData()
{
  IDCollection comuni of Comune = new()
  for each row (readonly)
  {
    select
      descrComune = DESCRCOMUNE
      codProvincia = CODPROVINCIA
      codStato = CODSTATO
      cap = CAP
      descrStato = subquery
         select top 1 // 
           DESCRSTATO
         from 
           TABSTATI // master table
         where
           TABSTATI.CODSTATO == TABCOMUNI.CODSTATO
      descrProvincia = subquery
         select top 1 // 
           DESCRPROVINCIA
         from 
           TABPROVINCE // master table
         where
           TABPROVINCE.CODPROVINCIA == TABCOMUNI.CODPROVINCIA
    from 
      TABCOMUNI // master table
     
    Comune c = new()
    c.DESCRCOMUNE = descrComune
    c.CODPROVINCIA = codProvincia
    c.CODSTATO = codStato
    c.CAP = cap
    c.ProvinciaDescription = descrProvincia
    c.StateDescription = descrStato
    c.setOriginal()
    comuni.add(c)
  }
  Comuni.setCollection(comuni, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ComuniSelection.select()
{
  this.close(true)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event ComuniSelection.Load()
{
  Comuni.listQBE = Row
  this.closeOnSelection = false
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event ComuniSelection.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm == true)
  {
    Comune selectedComune = Comuni.document
    if (selectedComune and selectedComune.DESCRCOMUNE != "" and selectedComune.DESCRCOMUNE != null)
    {
      int idxComune = this.PropertiesToBeSet.getValue("comune")
      int idxCap = this.PropertiesToBeSet.getValue("cap")
      int idxCodProvincia = this.PropertiesToBeSet.getValue("codprovincia")
      int idxCodStato = this.PropertiesToBeSet.getValue("codstato")
      if (idxComune >= 0)
      {
         this.Module.setProperty(idxComune, selectedComune.DESCRCOMUNE)
      }
      if (idxCap >= 0)
      {
         this.Module.setProperty(idxCap, selectedComune.CAP)
      }
      if (idxCodProvincia >= 0)
      {
         this.Module.setProperty(idxCodProvincia, selectedComune.CODPROVINCIA)
      }
      if (idxCodStato >= 0)
      {
         this.Module.setProperty(idxCodStato, selectedComune.CODSTATO)
      }
    }
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event ComuniSelection.Comuni.OnDynamicProperties()
{
  Comune c = Comuni.document
  if (c and c.DESCRCOMUNE != "" and c.DESCRCOMUNE != null and this.PreviousSelection != "" and this.PreviousSelection != null and c.DESCRCOMUNE == this.PreviousSelection)
  {
    Comuni.DESCRCOMUNE.textColor = RGBColor(0, 0, 255, ...)
    Comuni.CAP.textColor = RGBColor(0, 0, 255, ...)
    Comuni.ProvinciaDescription.textColor = RGBColor(0, 0, 255, ...)
    Comuni.StateDescription.textColor = RGBColor(0, 0, 255, ...)
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event ContactsOrgchartSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  this.HandleContactMessages(Message, Doc)
}


// ──────────────────────────────────

// *********************************************************************************
// Event raised by the form object in web applications when a modal window is closed
// *********************************************************************************
event ContactsOrgchartSubform.EndModal(
  int LookupForm       // An integer that identifies the modal form that was just closed, using the Me function of the form object to make the comparison.
  boolean Result       // True if the user confirmed the choice, closing the model form using the confirmation button on the title bar; otherwise False. The form can also be closed using the form object's Cl...
  inout boolean Cancel // If set to True, any subsequent automatic processing will be canceled. In this case, the framework will not attempt to automatically transfer the data from the modal form to the call...
)
{
  if (LookupForm == ContactDetail.me() and Result == true)
  {
    Contatto contatto = this.getObjectTag("contact_edit_form_result")
    if (contatto.deleted)
    {
      this.OrgchartController.removeContact(contatto)
    }
    else 
    {
      this.OrgchartController.updateContact(this.getObjectTag("contact_edit_form_result"))
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ContactsOrgchartSubform.HandleContactMessages(
  string Message      // 
  IDDocument document // 
)
{
  switch (Message)
  {
    case "LOAD":
      this.loadData(document)
    break
    case editNode:
      this.openContact(document)
    break
    case nodeClick:
      this.openContact(document)
    break
    case DeleteNodeRequest:
      this.deleteContact(document)
    break
    case AddNodeRequest:
      this.addContact(document)
    break
    case AddAssistantNodeRequest:
      this.addContact(document)
    break
    case ChangeNodeParent:
      this.alignNewNodeParent(document)
    break
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ContactsOrgchartSubform.openContact(
  IDDocument node // 
)
{
  Node n = (Node)node
  Contatto linkedContatto = cast(n.LinkedObjectInstance)
  ContactDetail.showForm(linkedContatto, this)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ContactsOrgchartSubform.deleteContact(
  IDDocument node // 
)
{
  Node n = (Node)node
  Contatto linkedContatto = cast(n.LinkedObjectInstance)
   
  boolean contactHasChildren = this.OrgchartController.contactHasChildren(linkedContatto)
  if (contactHasChildren)
  {
    UIBusinessLogic.messageBox("Il contatto è <b>padre</b>, sposta o elimina i suoi figli.")
  }
  else 
  {
    this.askConfirmationForDeletion(linkedContatto)
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ContactsOrgchartSubform.alignNewNodeParent(
  IDDocument argNode // 
)
{
  Node nodeWithNewParent = (Node)argNode
  this.OrgchartController.alignNodeParent(nodeWithNewParent)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ContactsOrgchartSubform.loadData(
  IDDocument document // 
)
{
  Clifor c = (Clifor)document
  this.OrgchartController = OrgchartController.create(c, this, Orgchart.IDForm())
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ContactsOrgchartSubform.askConfirmationForDeletion(
  Contatto contact // 
)
{
  int answer = UIBusinessLogic.messageConfirmEx(formatMessage("Confermi di voler <font color=red>eliminare</font> il contatto <b>|1 |2<b> |3", contact.COGNOME, contact.NOME, contact.EMAIL, ...), "Sì;No")
  if (answer == 1)
  {
    this.OrgchartController.removeContact(contact)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ContactDetail.showForm(
  Contatto contact // Write a comment for this parameter or press backspace to delete this comment
  IDForm caller    // 
)
{
  this.Caller = caller
  Contact.setDocument(contact, true)
  this.show(Modal)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ContactDetail.Confirm()
{
  this.close(true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ContactDetail.selectAFunction()
{
  OrgchartFunctionsSelections.ShowForm(this)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ContactDetail.delete()
{
  if (Contact.document)
  {
    Contatto c = Contact.document
    string ruoloInfo = if(c.RUOLO != "", "(" + c.RUOLO + ")", "")
    int answer = UIBusinessLogic.messageConfirmEx(formatMessage("Confermi di voler eliminare il contatto |2?", ruoloInfo, ...), "Sì;No")
    if (answer == 1)
    {
      c.deleted = true
      this.close(true)
    }
  }
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event ContactDetail.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm == true)
  {
    Contatto c = Contact.document
    this.Caller.setObjectTag("contact_edit_form_result", c)
  }
  else 
  {
    this.Caller.setObjectTag("contact_edit_form_result", null)
  }
}


// ──────────────────────────────────

// *********************************************************************************
// Event raised by the form object in web applications when a modal window is closed
// *********************************************************************************
event ContactDetail.EndModal(
  int LookupForm       // An integer that identifies the modal form that was just closed, using the Me function of the form object to make the comparison.
  boolean Result       // True if the user confirmed the choice, closing the model form using the confirmation button on the title bar; otherwise False. The form can also be closed using the form object's Cl...
  inout boolean Cancel // If set to True, any subsequent automatic processing will be canceled. In this case, the framework will not attempt to automatically transfer the data from the modal form to the call...
)
{
  if (LookupForm == OrgchartFunctionsSelections.me() and Result == true)
  {
    Funzione f = this.getObjectTag("result_orgchart_functions_lookup")
    if (f)
    {
      Contatto c = Contact.document
      c.RUOLO = f.CODFUNZIONE
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void OrgchartFunctionsSelections.ShowForm(
  IDForm caller // Write a comment for this parameter or press backspace to delete this comment
)
{
  this.Caller = caller
  IDCollection funny of Funzione = new()
  for each row (readonly)
  {
    select
      functionID = Funzioni.IDFUNZIONE
    from 
      Funzioni      // master table
      OrgchartNodes // joined with Funzioni using key FK_MSQ_ORG_FUNZIONI01
    where
      !(isNull(Funzioni.CODFUNZIONE))
      Funzioni.ATTIVA == Yes
    order by
      Funzioni.CODFUNZIONE
     
    Funzione fun = Funzione.getFromDB(functionID, ...)
    fun.setOriginal()
    funny.add(fun)
  }
  Funzioni.setCollection(funny, true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void OrgchartFunctionsSelections.Select()
{
  this.close(true)
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event OrgchartFunctionsSelections.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm and Funzioni.document)
  {
    Funzione result = Funzioni.document
    this.Caller.setObjectTag("result_orgchart_functions_lookup", result)
  }
  else 
  {
    this.Caller.setObjectTag("result_orgchart_functions_lookup", null)
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event OrgchartFunctionsSelections.Load()
{
  Funzioni.listQBE = Row
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void PersonaleDetailSubform.modifyComune()
{
  Personale p = PersonaleInfo.document
  if (p and p.IDDIPENDENTE > 0)
  {
    int comuneIndex = p.getPropertyIndex("COMUNE", true, true, true, true)
    int capIndex = p.getPropertyIndex("CAP", true, true, true, true)
    int provinciaIndex = p.getPropertyIndex("CODPROVINCIA", true, true, true, true)
    int statoIndex = p.getPropertyIndex("CODSTATO", true, true, true, true)
    ComuniSelection.showForm(p.COMUNE, p, comuneIndex, capIndex, provinciaIndex, statoIndex)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void PersonaleDetailSubform.modifyNascita()
{
  Personale p = PersonaleInfo.document
  if (p and p.IDDIPENDENTE > 0)
  {
    int luogoNascitaIndex = p.getPropertyIndex("LUOGONASCITA", true, true, true, true)
    int stateNascitaIndex = p.getPropertyIndex("CODSTATONASC", true, true, true, true)
    int codProvinciaNascitaIndex = p.getPropertyIndex("CODPROVINASC", true, true, true, true)
    ComuniSelection.showForm(p.COMUNE, p, luogoNascitaIndex, ..., codProvinciaNascitaIndex, stateNascitaIndex)
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event PersonaleDetailSubform.Load()
{
  PersonaleInfo.collapsable = false
  caratterizzazioniPanel.layout = List
  caratterizzazioniPanel.collapsable = false
  PersonaleInfo.DATANASCITA.mask = UIParameters.getDateFormat()
  PersonaleInfo.DATAASSUNZIONE.mask = UIParameters.getDateFormat()
  PersonaleInfo.DATASCADENZAPROVA.mask = UIParameters.getDateFormat()
  PersonaleInfo.DATACESSAZIONE.mask = UIParameters.getDateFormat()
}


// ──────────────────────────────────



// ──────────────────────────────────

// *********************************************************************************
// Event raised by the form object in web applications when a modal window is closed
// *********************************************************************************
event PersonaleDetailSubform.EndModal(
  int LookupForm       // An integer that identifies the modal form that was just closed, using the Me function of the form object to make the comparison.
  boolean Result       // True if the user confirmed the choice, closing the model form using the confirmation button on the title bar; otherwise False. The form can also be closed using the form object's Cl...
  inout boolean Cancel // If set to True, any subsequent automatic processing will be canceled. In this case, the framework will not attempt to automatically transfer the data from the modal form to the call...
)
{
  if (LookupForm == ComuniSelection.me())
  {
    Comune c = this.getObjectTag("comune_lookup_result")
    Personale p = PersonaleInfo.document
    if (p and p.IDDIPENDENTE > 0 and c)
    {
      p.COMUNE = c.DESCRCOMUNE
      p.CAP = c.CAP
      p.CODPROVINCIA = c.CODPROVINCIA
      p.CODSTATO = c.CODSTATO
    }
  }
}


// ──────────────────────────────────

// **************************************************************************************************************************
// Event raised by the panel after saving the file uploaded by the user to the database or deleting the contents of the blob.
// **************************************************************************************************************************
event PersonaleDetailSubform.PersonaleInfo.AfterBLOBUpdate(
  int Column       // An integer specifying which panel field is involved in the update or delete operation. It should be compared with the Me function of the panel fields.
  int Size         // Size of the uploaded file in bytes, or -1 if the contents of the blob have been deleted.
  string Extension // A string containing the extension of the file being loaded.
)
{
  this.showPicture(Extension)
   
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event CarrieraSubform.Load()
{
  Carriera.DADATA.mask = UIParameters.getDateFormat()
  Carriera.ADATA.mask = UIParameters.getDateFormat()
   
  FunzioneMembers.collapsable = false
  Carriera.collapsable = false
   
  Carriera.setCommandEnabled(Update, false)
  Carriera.setCommandEnabled(Navigate, false)
  Carriera.setCommandEnabled(Search, false)
  Carriera.setCommandEnabled(Duplicate, false)
  Carriera.setCommandEnabled(Refresh, false)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event CarrieraSubform.Carriera.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    Cancel = true
    this.insertCarriera()
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event CarrieraSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message = "LOAD")
  {
    Personale p = (Personale)Doc
    this.handleLoadMessage(p)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CarrieraSubform.handleLoadMessage(
  Personale personale // 
)
{
  this.Personale = personale
   
  this.Personale.loadPersonaleCarriera(...)
  Personale.PERCARRIERE.addSortCriteria(Carriera.DADATA)
  Personale.PERCARRIERE.doSort()
  Carriera.setCollection(this.Personale.PERCARRIERE, true)
   
  this.Personale.loadPersonaleFunzioniRicoperte(...)
  FunzioneMembers.setCollection(this.Personale.MSQPERSFUNZIONI, true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void CarrieraSubform.insertCarriera()
{
  IDCollection carriereCollection of Carriera = Carriera.collection
   
  if (this.Personale)
  {
    Carriera emptyCarriera = Carriera.create(this.Personale)
    carriereCollection.add(emptyCarriera)
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event NotePersonaleSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message = "LOAD")
  {
    this.handleLoadMessage(Doc)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void NotePersonaleSubform.handleLoadMessage(
  IDDocument doc // 
)
{
  Personale p = cast(doc)
  if (p)
  {
    int noteHtmlPropertyIndex = p.getPropertyIndex("NOTEHTML", true, true, true, true)
    HTMLEditorConfiguration htmlec = HTMLEditorConfiguration.create(500, p, noteHtmlPropertyIndex, false)
    IDForm htmlEditorSubform = getDevextremeSubformInstance(html)
    Note.LabelNote.setLabelSubForm(htmlEditorSubform, ...)
    htmlEditorSubform.sendMessage(configuration, htmlec, ...)
    p.updated = false
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event EventiDetailSubform.Load()
{
  EventiInfo.collapsable = false
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event EventiDetailSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "LOAD":
      this.handleLoadMessage(Message, Doc, Sender)
    break
    case LOCK_PANELS:
      Evento e = EventiInfo.document
      e.setOriginal()
      EventiInfo.locked = true
    break
    case UNLOCK_PANELS:
      EventiInfo.locked = false
    break
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event EventiDetailSubform.EventiInfo.OnDynamicProperties()
{
  // set the title and main info inside the first row
   
  string titleEvento = "<span class='firstRow-title'>" + EventiInfo.DESCRTITOLO + "</span>"
  string infoEvento = "<span class='firstRow-info'>" + EventiInfo.NROEVENTO + " · " + toString(EventiInfo.DATAEVENTO) + " · " + EventiInfo.DESCRCLASSE.text + "</span>"
  EventiInfo.LabelTitoloEvento.caption = titleEvento + "<br>" + infoEvento
   
  string statoText = "<span class=stato-" + replace(EventiInfo.DESCRSTATOEVENTO.text, " ", "") + ">" + EventiInfo.DESCRSTATOEVENTO.text + "</span>"
  EventiInfo.LabelStatoEvento.caption = statoText
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventiDetailSubform.handleLoadMessage(
  string Message // 
  IDDocument Doc // 
  IDForm caller  // 
)
{
  Evento e = (Evento)Doc
  if (Message == "LOAD" and Evento.isMyInstance(Doc))
  {
    try 
    {
      EventiInfo.setDocument(e, ...)
      EventiInfo.lockunlocknroeventobtn.caption = "{{icon-fa-lock fa-solid}}"
      EventiInfo.NROEVENTO.setEnabled(false)
    }
    catch 
    {
      UIBusinessLogic.DTTLogMessage(formatMessage("HTML Editor init error: !1", errorMessage(), ...), errorNumber(), DTTError)
    }
  }
   
  boolean shouldHtmlFieldBeLocked = e.isClosed()
   
  // setup HTML editor for descrizione evento HTML
  int descrizionePropIndex = e.getPropertyIndex("DESCEVENHTML", true, true, true, true)
  HTMLEditorConfiguration conf = HTMLEditorConfiguration.create(450, e, descrizionePropIndex, shouldHtmlFieldBeLocked)
  IDForm htmlEditorSubform = getDevextremeSubformInstance(html)
  EventiInfo.LabelDescrizione.setLabelSubForm(htmlEditorSubform, ...)
  htmlEditorSubform.sendMessage(configuration, conf, ...)
   
  e.updated = false
   
  if (caller)
  {
    this.CallerForm = caller
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventiDetailSubform.OpenModelloEventoForm()
{
  ModelloEvento me = ModelloEvento.getFromDB(EventiInfo.IDTEMPLATEEVENTO, ...)
  me.openDetailForm()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventiDetailSubform.DESCRTITOLOModello()
{
  this.OpenModelloEventoForm()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventiDetailSubform.lockunlocknroeventobtn()
{
  if (EventiInfo.lockunlocknroeventobtn.caption == "{{icon-fa-lock-open fa-solid}}")
  {
    EventiInfo.lockunlocknroeventobtn.caption = "{{icon-fa-lock fa-solid}}"
    EventiInfo.NROEVENTO.setEnabled(false)
    return 
  }
   
  if (EventiInfo.lockunlocknroeventobtn.caption == "{{icon-fa-lock fa-solid}}")
  {
    EventiInfo.lockunlocknroeventobtn.caption = "{{icon-fa-lock-open fa-solid}}"
    EventiInfo.NROEVENTO.setEnabled(true)
    return 
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DisposizioniSubform.Load()
{
  EventiDisposizioniQuickviewPanel.collapsed = false
  EventiDisposizioniQuickviewPanel.collapsable = false
  EventiDisposizioniQuickviewPanel.RiapriDisposizione.text = "{{icon-fa-eraser fa-solid}}"
   
   
}


// ──────────────────────────────────



// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event DisposizioniSubform.EventiDisposizionipanel.OnChangeRow()
{
   
  Disposizione d = EventiDisposizionipanel.document
   
  // Defensive: panel transiently reports document==null during modal-close repaint. Don't clobber a valid SelectedDisposizione in that case
  if (d == null)
    return 
   
  if (d != null and d.IDATTIVITA > 0)
  {
    EventiDisposizioniQuickviewPanel.setDocument(d, true)
    EventiDisposizionipanel.canDrag = d.canDrag(this.Evento)
    this.computeAndApplyCommandVisibilty()
    this.setVisibilityOfAddCommand()
     
  }
  else 
    EventiDisposizioniQuickviewPanel.visible = false
}


// ──────────────────────────────────



// ──────────────────────────────────

// ***********************************************************************************************************************************************
// After an object is successfully dragged and dropped onto this panel, this event is raised by the panel to allow the dragged data to be prepared
// ***********************************************************************************************************************************************
event DisposizioniSubform.EventiDisposizionipanel.OnGenericDrop(
  string DragInfo      // A string parameter, set by the OnGenericDrag event, which specifies the data involved in the drag & drop operation.
  inout boolean Cancel // A boolean output parameter that can be set to True to prevent the default action of the framework. Although a panel has no default action, setting the parameter to True is recommend...
  int:mouseButtons Button // Represents the mouse button used to perform the drag & drop. The possible values are provided in the MouseButtons list.
  int X                // The X position in pixels relative to the panel where the object was dropped.
  int Y                // The Y position in pixels relative to the panel where the object was dropped.
  int XB               // The X position in pixels relative to the browser where the object was dropped.
  int YB               // The Y position in pixels relative to the browser where the object was dropped.
  int Column           // The index of the field accepting the drop. Use the field's Me object to compare the value of this argument. This may be -1 if the drop takes place outside the fields.
  int Row              // The number of the panel row on which the drop occurred. The possible range is zero to VisibleRows -1, or -1 if the drop takes place outside the fields.
  IDDocument Doc       // The document underlying the row that accepted the drop. It can be NullObject if the object was dropped outside the fields or on an empty row, or if the panel is not DO.
)
{
  Cancel = true
  if (DragInfo == null or DragInfo == "")
    return 
   
  Disposizione targetDisposizione = (Disposizione)Doc
  if (targetDisposizione == null)
    return 
  else 
  {
    if (!(targetDisposizione.canDropOn(this.Evento)))
      return 
  }
  int sourceIdAttivita = toInteger(DragInfo)
   
   
  Disposizione source = this.Evento.getMatchingDisposizione(sourceIdAttivita)
  if (source == null)
    return 
  source.moveTo(this.Evento, targetDisposizione)
}


// ──────────────────────────────────

// ********************************************************************************************************************************************************************
// After a panel field is successfully dragged and dropped onto a target frame, this event is raised by the panel to allow the data to be prepared for the target frame
// ********************************************************************************************************************************************************************
event DisposizioniSubform.EventiDisposizionipanel.OnGenericDrag(
  inout string DragInfo   // It is a string type output parameter. The value set will be passed to the OnGenericDrop event to indicate the data involved in the drag&drop.
  int:mouseButtons Button // Represents the mouse button used to perform the drag & drop. The possible values are provided in the MouseButtons list.
  int Column              // The index of the field dragged. Use the field's Me object to compare the value of this argument.
)
{
  Disposizione source = EventiDisposizionipanel.document
  if (source and source.canDrag(this.Evento))
  {
    DragInfo = toString(source.IDATTIVITA)
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event DisposizioniSubform.EventiDisposizioniQuickviewPanel.OnDynamicProperties()
{
  Disposizione d = EventiDisposizionipanel.document
   
  EventiDisposizioniQuickviewPanel.DescriptionMultiSourceResponsible.setEnabled(false)
  EventiDisposizioniQuickviewPanel.IDTIPOATTIVITA.setEnabled(false)
  EventiDisposizioniQuickviewPanel.CHKBTN.setEnabled(false)
  EventiDisposizioniQuickviewPanel.DATAPREVISTA.setEnabled(false)
  EventiDisposizioniQuickviewPanel.OraInizio.setEnabled(false)
  EventiDisposizioniQuickviewPanel.OraFine.setEnabled(false)
  EventiDisposizioniQuickviewPanel.ORE.setEnabled(false)
  EventiDisposizioniQuickviewPanel.DESCRATTIVITA.setEnabled(false)
  EventiDisposizioniQuickviewPanel.NOTIFICA.setEnabled(false)
   
  // disable reopen closed disposizione as default
  EventiDisposizioniQuickviewPanel.RiapriDisposizione.setVisible(false)
   
  if (d)
  {
    EventiDisposizioniQuickviewPanel.CHKBTN.CSSClass = d.GetChecklistCssClassForIcon()
    EventiDisposizioniQuickviewPanel.CHKBTN.text = d.GetChecklistTextIconForIcon()
     
    if (!(d.isClosed()))
    {
      EventiDisposizioniQuickviewPanel.DescriptionMultiSourceResponsible.setEnabled(true)
      EventiDisposizioniQuickviewPanel.IDTIPOATTIVITA.setEnabled(true)
      EventiDisposizioniQuickviewPanel.CHKBTN.setEnabled(true)
      EventiDisposizioniQuickviewPanel.DATAPREVISTA.setEnabled(true)
      EventiDisposizioniQuickviewPanel.OraInizio.setEnabled(true)
      EventiDisposizioniQuickviewPanel.OraFine.setEnabled(true)
      EventiDisposizioniQuickviewPanel.ORE.setEnabled(true)
      EventiDisposizioniQuickviewPanel.DESCRATTIVITA.setEnabled(true)
      EventiDisposizioniQuickviewPanel.NOTIFICA.setEnabled(true)
    }
     
    // Mirror visibility from the row-level command set; central rule lives in Disposizione.computeCommandVisibility
    EventiDisposizioniQuickviewPanel.RiapriDisposizione.setVisible(RiapriDisposizione.visible)
  }
   
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event DisposizioniSubform.EventiDisposizioniQuickviewPanel.OnChangeRow()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    EventiDisposizioniQuickviewPanel.RiapriDisposizione.setVisible(RiapriDisposizione.visible)
  }
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void DisposizioniSubform.handleLoadMessage(
  string Message // 
  IDDocument Doc // 
  IDForm sender  // 
)
{
  if (Message == "LOAD" and Evento.isMyInstance(Doc))
  {
    try 
    {
      this.Evento = (Evento)Doc
      this.forcefullyLoadDisposizioni()
       
      UIBusinessLogic.DTTLogMessage("Evento id: " + toString(this.Evento.IDEVENTO), ...)
      UIBusinessLogic.DTTLogMessage("Disposizioni count: " + toString(this.Evento.Disposizioni.count()), ...)
       
      this.ParentIDForm = sender
    }
     
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.openDisposizioneClosureForm()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    if (!(saveIfModified()))
      return 
     
    boolean uncompletedChecklist = d.hasChecklistAtLeastOneRowWithoutResult()
     
    if (uncompletedChecklist)
    {
      UIBusinessLogic.messageBox("Compilare la checklist prima di chiudere la disposizione.")
      return 
    }
     
    if (this.Evento.isNormaleType())
    {
      DisposizioneNormaleCloseForm dlcf = DisposizioneNormaleCloseForm.newInstance(Modal, ...)
      dlcf.ShowForm(d, this.ParentIDForm)
      dlcf.show(Modal)
    }
     
    if (this.Evento.isWorkflowType())
    {
      DisposizioneWorkflowCloseForm dcf = DisposizioneWorkflowCloseForm.newInstance(Modal, ...)
      dcf.ShowForm(d, this.ParentIDForm, this.IDForm(), this.Evento)
      dcf.show(Modal)
    }
  }
   
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void DisposizioniSubform.RollbackSelectedDisposizione()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
     
    int i = UIBusinessLogic.messageConfirmEx("ATTENZIONE: Il rollback eliminerà le disposizioni successive a quella selezionata con relativi esiti e note. Nel caso un esito di checklist abbia determinato la 
             creazione di un evento, questo non verrà cancellato, ma verrà eliminato il riferimento che c'era tra questo evento e l'evento creato. Confermi l'esecuzione del rollback?", "Sì;No")
    if (i == 1)
    {
      this.Evento.rollbackToSelectedDisposizione(d, normalMode)
      this.ParentIDForm.sendMessage("refreshDiagram", ...)
    }
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.reOpenDisposizione()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    int confirm = UIBusinessLogic.messageConfirmEx("Riaprire questa disposizione? La data di chiusura, l'esito e le note di chiusura verranno cancellati.", "Si;No")
    if (confirm == 1)
    {
      d.reOpen()
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.forcefullyLoadDisposizioni()
{
  Evento.Disposizioni.loaded = false
  this.Evento.loadCollectionFromDB(this.Evento.Disposizioni, ...)
  this.Evento.sortDisposizioniByNroRiga()
   
  EventiDisposizionipanel.setCollection(this.Evento.Disposizioni, true)
  this.computeAndApplyCommandVisibilty()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.CloseMultipleDisposizione()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    if (!(saveIfModified()))
      return 
     
    if (d.isLastOpenMultipleDisposizione(this.Evento))
    {
      this.openDisposizioneClosureForm()
    }
    else 
    {
      MultipleDisposizioneCloseForm mdcf = MultipleDisposizioneCloseForm.newInstance(Modal, ...)
      mdcf.showForm(d)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.AddDisposzioni()
{
  this.DisposizioneToBeInserted = false
  TipoDisposizioneSelection.showForm(this.Evento.IDCLASSE, this)
}


// ──────────────────────────────────

// **************************************************************************
// Handler for the Insert command — inserts a new disposizione before the
// currently-selected one. Visibility is controlled by
// Disposizione.computeCommandVisibility (Normal evento + selected row only).
// **************************************************************************
public void DisposizioniSubform.InsertDisposizione()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    this.DisposizioneToBeInserted = true
    TipoDisposizioneSelection.showForm(this.Evento.IDCLASSE, this)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.RemoveDisposizione()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    this.Evento.removeDisposizione(d)
    EventiDisposizioniQuickviewPanel.visible = false
    this.computeAndApplyCommandVisibilty()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private boolean DisposizioniSubform.saveIfModified()
{
  boolean continue = true
  boolean docIsModified = this.Evento.isModified(...)
  if (docIsModified)
  {
    int i = UIBusinessLogic.messageConfirmEx("Desideri salvare le modifiche apportate?", "Sì;No")
    if (i == null)
      return null
     
    if (i == 1)
    {
      DevTools.RefactoringOpportunity("We call here Evento.Validate and at the end "SendMessage("SAVE") also call mainModule.Validate at parent formSide, so in principal it is a redundent call")
      boolean isValid = this.Evento.validate(...)
       
      // send message to parent form (Eventi Detail form) to display errors
      this.ParentIDForm.sendMessage("SAVE", ...)
       
      continue = isValid
    }
    else 
    {
      continue = false
    }
  }
  return continue
}


// ──────────────────────────────────

// ****************************************************************************************************************************************************************************************************************
// It's a public method, called from two places (OnMouseClick, OnDynamicProperties). Worth documenting that it's the centralized panel-level Add visibility logic, dispatching by evento type. Two-line comment,
// makes the intent obvious.
// ****************************************************************************************************************************************************************************************************************
public void DisposizioniSubform.setVisibilityOfAddCommand()
{
  boolean show = false
  if (this.Evento)
    show = this.Evento.canAddDisposizioneFromPanel(QappCore.Loggeduser)
  DisposizioniCommandSet.setCommandVisible(AddDisposzioni.getIndex(), show)
}


// ──────────────────────────────────

// ****************************************************************************************************************************************************************************************************************
// This method maps every command in the set to its corresponding flag. Adding a new command requires both extending DisposizioneCommandVisibility and adding a line here." Anchors the contract for future
// contributors who'll otherwise add a flag and forget the wiring.
// ****************************************************************************************************************************************************************************************************************
public void DisposizioniSubform.applyRowCommandVisibility(
  DisposizioneCommandVisibility dcv // 
)
{
   
  if (dcv)
  {
    DisposizioniCommandSet.setCommandVisible(Checklist.getIndex(), dcv.ShowChecklist)
    DisposizioniCommandSet.setCommandVisible(InsertDisposizione.getIndex(), dcv.InsertDisposizione)
    DisposizioniCommandSet.setCommandVisible(RemoveDisposizione.getIndex(), dcv.RemoveDisposizione)
    DisposizioniCommandSet.setCommandVisible(DuplicateDisposizione.getIndex(), dcv.DuplicateDisposizione)
    DisposizioniCommandSet.setCommandVisible(DuplicateMultipleDisposizione.getIndex(), dcv.DuplicateMultipleDisposizione)
    DisposizioniCommandSet.setCommandVisible(CloseDisposizione.getIndex(), dcv.CloseDisposizione)
    DisposizioniCommandSet.setCommandVisible(CloseMultipleDisposizione.getIndex(), dcv.CloseMultipleDisposizione)
    DisposizioniCommandSet.setCommandVisible(RiapriDisposizione.getIndex(), dcv.ReopenDisposizione)
    DisposizioniCommandSet.setCommandVisible(Rollback.getIndex(), dcv.Rollback)
    DisposizioniCommandSet.setCommandVisible(MoveUp.getIndex(), dcv.MoveUp)
    DisposizioniCommandSet.setCommandVisible(MoveDown.getIndex(), dcv.MoveDown)
     
    // Mirror visibility from the row-level command set; central rule lives in Disposizione.computeCommandVisibility
    EventiDisposizioniQuickviewPanel.RiapriDisposizione.setVisible(RiapriDisposizione.visible)
  }
  else 
  {
    DisposizioniCommandSet.setCommandVisible(Checklist.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(InsertDisposizione.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(RemoveDisposizione.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(DuplicateDisposizione.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(DuplicateMultipleDisposizione.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(CloseDisposizione.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(CloseMultipleDisposizione.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(RiapriDisposizione.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(Rollback.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(MoveUp.getIndex(), false)
    DisposizioniCommandSet.setCommandVisible(MoveDown.getIndex(), false)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.DuplicateDisposizione()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    Disposizione newDisp = d.duplicateDisposizione(QappCore.Loggeduser, this.Evento, today(), ...)
     
    IDCollection allDisposizioniCollectionInsidePanel of Disposizione = EventiDisposizionipanel.collection
    allDisposizioniCollectionInsidePanel.add(newDisp)
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.MoveUp()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    d.moveUp(this.Evento)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.MoveDown()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    d.moveDown(this.Evento)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DisposizioniSubform.add(
  TipoDisposizione tipoDisposizione // 
)
{
  Disposizione d = Disposizione.create(this.Evento)
  if (d)
  {
    d.IDTIPOATTIVITA = tipoDisposizione.IDTIPOATTIVITA
    d.DESCRATTIVITA = tipoDisposizione.DESCRDEFAULT
    d.NRORIGA = this.Evento.GetNextNroRigaForDisposizione()
     
    IDCollection coll of Disposizione = EventiDisposizionipanel.collection
    coll.add(d)
//     
    // set the focus on the just added object
    EventiDisposizionipanel.findDocument(d)
     
    EventiDisposizioniQuickviewPanel.visible = true
    EventiDisposizioniQuickviewPanel.setDocument(d, true)
    this.computeAndApplyCommandVisibilty()
    DevTools.ToBeReviewed("when Aggiungi done via mouse right click->Aggiungi, it does not focus on added record")
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void DisposizioniSubform.insert(
  TipoDisposizione tipoDisposizione // 
)
{
  Disposizione d = EventiDisposizionipanel.document
  if (d)
  {
    Disposizione insertedDisposizione = this.Evento.insertDisposizioneBefore(d, tipoDisposizione)
    this.DisposizioneToBeInserted = false
     
     
    // Note: no findDocument needed here — insertDisposizioneBefore handles the panel's row positioning internally (unlike add()).
     
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioniSubform.computeAndApplyCommandVisibilty()
{
  Disposizione d = EventiDisposizionipanel.document
  if (d != null and d.IDATTIVITA > 0)
  {
    DisposizioneCommandVisibility dcv = null
    dcv = d.computeCommandVisibility(this.Evento, QappCore.Loggeduser)
    this.applyRowCommandVisibility(dcv)
  }
  else 
  {
    this.applyRowCommandVisibility(null)
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event DisposizioneWorkflowCloseForm.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  UIBusinessLogic.DTTLogMessage(formatMessage("Message: |1 |2 |3", Message, Par3, JSON.stringify(Doc), ...), ...)
  if (Message == "RETURN_RENDERED_CDATA_COUNT")
  {
    int renderedCdataCount = toInteger(Par1)
    cdatapanel.visible = renderedCdataCount > 0
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event DisposizioneWorkflowCloseForm.Load()
{
  Optionspanel.collapsable = false
  Infopubbliche.collapsable = false
  nextMultipleDisposizioni.collapsable = false
  cdatapanel.collapsable = false
  NextDisposizione.collapsable = false
  eventoClosureWithoutEsito.collapsable = false
  EventoClosureWithEsito.collapsable = false
   
  nextMultipleDisposizioni.collapsed = false
  NextDisposizione.collapsed = false
  Infopubbliche.collapsed = false
   
  NextDisposizione.visible = false
  nextMultipleDisposizioni.visible = false
  Infopubbliche.visible = false
   
  cdatapanel.visible = false
  Optionspanel.visible = true
}


// ──────────────────────────────────



// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event DisposizioneWorkflowCloseForm.nextMultipleDisposizioni.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  if (Button == Right)
  {
    multipleDisposizioniCommandSet.openPopupXY(XB, YB)
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event DisposizioneWorkflowCloseForm.nextMultipleDisposizioni.OnDynamicProperties()
{
  if (nextMultipleDisposizioni.visible)
  {
    WkfDisposizioneDraft wdd = nextMultipleDisposizioni.document
    if (wdd)
    {
      nextMultipleDisposizioni.ExecutionDate.setEnabled(wdd.IsDateEditable)
      nextMultipleDisposizioni.TimeStartTime.setEnabled(wdd.IsDateEditable)
      nextMultipleDisposizioni.TimeEndTime.setEnabled(wdd.IsDateEditable)
      nextMultipleDisposizioni.DescriptionMultiSourceResponsible.setEnabled(wdd.IsExecutorEditable)
    }
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event DisposizioneWorkflowCloseForm.NextDisposizione.OnDynamicProperties()
{
  if (NextDisposizione.visible)
  {
    WkfDisposizioneDraft wdd = NextDisposizione.document
    if (wdd)
    {
      NextDisposizione.ExecutionDate.setEnabled(wdd.IsDateEditable)
      NextDisposizione.TimeStartTime.setEnabled(wdd.IsDateEditable)
      NextDisposizione.TimeEndTime.setEnabled(wdd.IsDateEditable)
      NextDisposizione.DescriptionMultiSourceResponsible.setEnabled(wdd.IsExecutorEditable)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.ShowForm(
  Disposizione disposizioneToClose // Write a comment for this parameter or press backspace to delete this comment
  IDForm sender                    // 
  IDForm mainDisposizioniForm      // 
  Evento evento                    // 
)
{
  NextDisposizione.visible = false
  nextMultipleDisposizioni.visible = false
  Infopubbliche.visible = false
  eventoClosureWithoutEsito.visible = false
  EventoClosureWithEsito.visible = false
   
   
  this.Disposizione = disposizioneToClose
  this.ParentIdForm = sender
  this.MainDisposizioniForm = mainDisposizioniForm
  this.Evento = evento
   
   
  this.LastSelectedIdResult = -1
   
  WkfStep ws = new()
  ws.IDSTEP = disposizioneToClose.IDSTEP
  ws.loadFromDB(...)
   
   
  for each WkfResult wr in ws.WKFRESULTS
  {
    Optionspanel.IDRESULT.addValueListItem(wr.IDRESULT, wr.RESULTDESCRIPTION, ...)
  }
   
//  this.Disposizione.IDRESULT = null
  Optionspanel.setDocument(this.Disposizione, true)
   
  if (ws.WKFRESULTS.count() == 1)
  {
    ws.WKFRESULTS.moveFirst()
    WkfResult wr = (WkfResult)ws.WKFRESULTS.getAt()
    Optionspanel.IDRESULT = wr.IDRESULT
  }
   
  Optionspanel.ConfermaMessage.text = formatMessage("|1, confermi l'esecuzione dell'impegno?<br>- Evento: |2<br>- Attività: |3", QappCore.Loggeduser.DESCRUTENTE, evento.DESCRTITOLO, disposizioneToClose.
           DESCRATTIVITA, ...)
}


// ──────────────────────────────────

// **************************************************************************************************************
// Check that all informations are inserted and everything is ok, than close the disposizione and close the modal
// **************************************************************************************************************
public void DisposizioneWorkflowCloseForm.ConfirmCloseDisposizione()
{
   
  boolean validPanelEntries = panelEntriesAreValid()
  if (validPanelEntries)
  {
    Utente currentUser = QappCore.Loggeduser
    int idSelectedResult = Optionspanel.IDRESULT
     
    IDCollection nextDisposizioni of WkfDisposizioneDraft = this.CurrentCloseContext.WkfDisposizioneDraft
    boolean closeResult = this.Disposizione.closeDisposizione(currentUser, normalMode, idSelectedResult, nextDisposizioni)
    if (closeResult)
    {
      this.close(...)
      this.MainDisposizioniForm.sendMessage("RELOAD_DISPOSIZIONI", ...)
      this.ParentIdForm.sendMessage("refreshDiagram", ...)
    }
     
    if (Infopubbliche.visible)
    {
      WkfPublicInfoDraft spid = Infopubbliche.document
      if (spid)
      {
         this.Disposizione.updateEventoPublicInfo(spid, ...)
      }
    }
     
    if (eventoClosureWithoutEsito.visible or EventoClosureWithEsito.visible)
    {
      int idGravita = this.CurrentCloseContext.FlowToNextStep.IDGRAVITA
      if (eventoClosureWithoutEsito.visible)
      {
         WkfFlow wf = eventoClosureWithoutEsito.document
         idGravita = wf.IDGRAVITA
      }
      this.Evento.setEventoAsClosed(currentUser, idGravita)
      this.Evento.saveToDB(0, ...)
      this.ParentIdForm.sendMessage("EVENTO_HAS_BEEN_CLOSED", ...)
    }
     
  }
   
   
   
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void DisposizioneWorkflowCloseForm.Dismiss()
{
  Disposizione.IDRESULT = null
  Disposizione.NOTECHIUSURA = ""
  this.close(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.Add()
{
   
  WkfStep nextStep = this.CurrentCloseContext.NextStep
  WkfFlow flowToNextStep = this.CurrentCloseContext.FlowToNextStep
  WkfDisposizioneDraft nd = DisposizioneClosureContext.createSingleDisposizione(this.Evento, nextStep, flowToNextStep, today())
  IDCollection allDisposizioni of WkfDisposizioneDraft = nextMultipleDisposizioni.collection
  allDisposizioni.add(nd)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.Delete()
{
  WkfDisposizioneDraft nd = nextMultipleDisposizioni.document
  if (nd)
  {
    nd.deleted = true
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void DisposizioneWorkflowCloseForm.OpenSelectExecutorModal()
{
  DevTools.RefactoringOpportunity("Change Personale to Utente")
  LookupHelper lh = LookupHelper.create(this.IDForm(), Personale, false, null, "EXECUTOR", ...)
  lh.displayLookup()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.loadCustomDataFromResult()
{
  this.CustomDataSubform = CustomDataSubform.newInstance(SubForm, ...)
  cdatapanel.Labelcdata.setLabelSubForm(this.CustomDataSubform, Form)
  Evento e = Evento.getFromDB(this.Disposizione.IDEVENTO, ...)
  string idResult = toString(Optionspanel.IDRESULT)
   
  if (toInteger(idResult) > 0)
  {
    this.CustomDataSubform.sendMessage("LOAD", e, "", "", "", idResult)
    this.CustomDataSubform.sendMessage("GET_RENDERED_CDATA_COUNT", ...)
  }
   
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.loadPanels()
{
  NextDisposizione.visible = false
  nextMultipleDisposizioni.visible = false
  eventoClosureWithoutEsito.visible = false
  EventoClosureWithEsito.visible = false
  Infopubbliche.visible = false
   
  switch (this.CurrentCloseContext.WokflowNextStepKind)
  {
    case NextStepIsStopWithEsito:
      this.loadEventoClosureWithEsitoPanel()
    break
    case NextStepIsStopWithoutEsito:
      this.loadEventoClosureWithoutEsitoPanel()
    break
    case NextStepWithSIngleDisposizione:
      this.loadNextDisposizionePanel()
    break
    case NextStepWithMultipleDisposizioni:
      this.loadNextMultipleDisposizionePanel()
    break
  }
   
  // display public info related information based on result
  this.loadInfoPubblichePanel()
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.loadInfoPubblichePanel()
{
   
  if (this.Evento.ModelloEvento.SUPPORTPUBLICINFO == Yes)
  {
    Infopubbliche.visible = true
    //  
    // display public info related information based on result
    WkfPublicInfoDraft spid = this.Disposizione.populateStepPublicInfoDraft(this.LastSelectedIdResult)
    Infopubbliche.IdPublicStatusInFlow.setEnabled(Infopubbliche.PUBLICSTATUSSELECTIONTYPE != ImpostaSpecifico)
    Infopubbliche.Notes.setEnabled(true)
    Infopubbliche.setDocument(spid, true)
  }
   
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.loadNextDisposizionePanel()
{
  CurrentCloseContext.WkfDisposizioneDraft.moveFirst()
  WkfDisposizioneDraft nd = (WkfDisposizioneDraft)this.CurrentCloseContext.WkfDisposizioneDraft.getAt()
  NextDisposizione.setDocument(nd, true)
  NextDisposizione.visible = true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.loadNextMultipleDisposizionePanel()
{
  nextMultipleDisposizioni.visible = true
  nextMultipleDisposizioni.setCollection(this.CurrentCloseContext.WkfDisposizioneDraft, true)
  nextMultipleDisposizioni.CurrentStepDescription.caption = "Descrizione" + ": " + this.CurrentCloseContext.NextStep.STEPDESCRIPTION
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.loadEventoClosureWithoutEsitoPanel()
{
  // create wkfFlow dummy instance to have lookup value for esito evento
  WkfFlow wf = new()
  wf.IDGRAVITA = this.CurrentCloseContext.FlowToNextStep.IDGRAVITA
  wf.IDTEMPLATEEVENTO = this.Evento.IDTEMPLATEEVENTO
  eventoClosureWithoutEsito.setDocument(wf, true)
  eventoClosureWithoutEsito.visible = true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneWorkflowCloseForm.loadEventoClosureWithEsitoPanel()
{
  EventoClosureWithEsito.visible = true
  EventoEsiti eventoEsiti = EventoEsiti.get(this.CurrentCloseContext.FlowToNextStep.IDGRAVITA)
  EventoClosureWithEsito.LabeldisplayText.text = formatMessage("Il workflow prevede ora la chiusura dell'evento con esito |1.", eventoEsiti.DESCRGRAVITA, ...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean DisposizioneWorkflowCloseForm.panelEntriesAreValid()
{
  boolean panelValuesAreValid = false
   
  // validate customdata
  CustomDataSubform cds = cast(this.CustomDataSubform)
  if (cds)
  {
    boolean validCustomData = cds.validateCustomData()
    if (!(validCustomData))
    {
      UIBusinessLogic.messageBox("Dati Personalizzati non validi, per favore controlla le sezioni evidenziate")
      return panelValuesAreValid
    }
  }
   
  int idSelectedResult = Optionspanel.IDRESULT
   
  if (idSelectedResult > 0)
  {
    IDCollection nextDisposizioni of WkfDisposizioneDraft = this.CurrentCloseContext.WkfDisposizioneDraft
     
    if (nextDisposizioni.count() > 0)
    {
      // validate all disposizioni input (single or multiple)
      for each WkfDisposizioneDraft nd in CurrentCloseContext.WkfDisposizioneDraft
      {
         boolean isValid = nd.validate(...)
         if (!(isValid))
         {
           UIBusinessLogic.messageBox("Disposizione non valida.")
           return panelValuesAreValid
         }
      }
    }
     
    if (Infopubbliche.visible)
    {
      WkfPublicInfoDraft spid = Infopubbliche.document
      if (spid)
      {
         if (spid.IdPublicStatusInFlow == null)
         {
           UIBusinessLogic.messageBox("È necessario selezionare lo stato pubblico.")
           return panelValuesAreValid
         }
      }
    }
     
     
    if (eventoClosureWithoutEsito.visible)
    {
      if (eventoClosureWithoutEsito.IDGRAVITA <= 0)
      {
         UIBusinessLogic.messageBox("Esito evento non è selezionato.")
         return panelValuesAreValid
      }
    }
     
    if (EventoClosureWithEsito.visible)
    {
      if (this.CurrentCloseContext.FlowToNextStep.IDGRAVITA <= 0)
      {
         UIBusinessLogic.messageBox("Esito evento non è selezionato.")
         return panelValuesAreValid
      }
    }
     
    panelValuesAreValid = true
  }
  else 
  {
    UIBusinessLogic.messageBox("E' necessario selezionare un esito per chiudere la disposizione.")
  }
   
  return panelValuesAreValid
}


// ──────────────────────────────────

// **************************************************************************************************************
// Check that all informations are inserted and everything is ok, than close the disposizione and close the modal
// **************************************************************************************************************
public void DisposizioneNormaleCloseForm.ConfirmCloseDisposizione()
{
  Utente currentUser = QappCore.Loggeduser
   
  boolean closeResult = this.Disposizione.closeDisposizione(currentUser, normalMode, null, ...)
   
  if (closeResult)
  {
    this.close(...)
  }
   
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void DisposizioneNormaleCloseForm.cancel()
{
   
  // resets the default (so in list we do not see esito after cancel)
  this.Disposizione.ESITO = null
  this.close(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DisposizioneNormaleCloseForm.ShowForm(
  Disposizione disposizioneToClose // 
  IDForm sender                    // 
)
{
  this.Disposizione = disposizioneToClose
  this.ParentIdForm = sender
   
   
  this.Disposizione.ESITO = Yes
  Optionspanel.document = this.Disposizione
   
  Optionspanel.ConfermaMessage.text = formatMessage("|1, confermi l'esecuzione dell'impegno? |2", QappCore.Loggeduser.DESCRUTENTE, disposizioneToClose.DESCRATTIVITA, ...)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event EventoChecklistForm.Load()
{
  EventoDomande.caption = ""
  EventoDomande.collapsable = false
  EventoDomande.collapsed = false
   
   
  EventoDomande.setErrorMode(Message, Message, Message, Message)
   
//  IDPanel idp = EventoDomande.IDPanel()
//  PanelRowButtonController prbc = PanelRowButtonController.create(idp, IDForm())
//  prbc.setup(left, ..., right, ChecklistCommandset.IDCommand())
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event EventoChecklistForm.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  if (Confirm)
  {
    boolean isCollectionValid = this.Checklist.isCollectionValid()
    if (!(isCollectionValid))
    {
      Cancel = true
    }
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event EventoChecklistForm.EventoDomande.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
   
  if (!(isNull(Row)) && Row >= 0)
  {
    IDCollection coll of ChecklistItem = EventoDomande.collection
    if (coll && coll.count() > 0)
    {
      ChecklistItem selected = (ChecklistItem)coll.getDirect(Row + 1)
      if (selected and !(this.Evento.isLocked()))
      {
         MoveDown.visible = false
         MoveUp.visible = false
          
         if (this.Checklist.CanMoveDownItem(selected))
           MoveDown.visible = true
          
         if (this.Checklist.CanMoveUpItem(selected))
           MoveUp.visible = true
          
         if (Button == Right)
         {
           ChecklistCommandset.caption = "Opzioni"
           ChecklistCommandset.openPopupXY(XB, YB)
         }
      }
    }
     
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void EventoChecklistForm.Add()
{
  this.Checklist.AddChecklistItem()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void EventoChecklistForm.Delete()
{
  if (EventoDomande.document)
  {
    ChecklistItem ci = EventoDomande.document
    this.Checklist.removeChecklistItem(ci)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void EventoChecklistForm.MoveUp()
{
  ChecklistItem checklistTemplate = EventoDomande.document
   
  if (checklistTemplate)
  {
    this.Checklist.moveUpItem(checklistTemplate)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void EventoChecklistForm.MoveDown()
{
  ChecklistItem checklistTemplateItem = EventoDomande.document
   
  if (checklistTemplateItem)
  {
    this.Checklist.moveDownItem(checklistTemplateItem)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventoChecklistForm.ShowForm(
  Disposizione ed     // 
  Evento parentEvento // 
)
{
  this.caption = formatMessage("|1 - Checklist", ed.DESCRATTIVITA, ...)
   
  this.Evento = parentEvento
  this.Checklist = ed.getChecklist()
  Checklist.ChecklistInstanceItemCollection.setOriginal()
   
  if (this.Checklist == null || Checklist.ChecklistInstanceItemCollection == null || this.Checklist.ChecklistTemplateType <= 0)
    UIBusinessLogic.DTTLogMessage("checklistTemplate is null", ..., DTTError)
   
  EventoDomande.setCollection(this.Checklist.ChecklistInstanceItemCollection, true)
   
  if (this.Evento.isLocked() or ed.isClosed())
  {
    Add.visible = false
    EventoDomande.locked = true
  }
  else 
  {
    Add.visible = true
    EventoDomande.locked = false
  }
   
   
  this.show(Modal)
   
  if (this.Evento.isLocked())
  {
    EventoDomande.locked = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventoChecklistForm.CloseForm()
{
  boolean validChecklist = this.Checklist.validate(...)
   
  if (validChecklist)
  {
    this.close(true)
  }
  else 
  {
    EventoDomande.showDocErrors(...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void MultipleDisposizioneCloseForm.ButtonOk()
{
  this.Disposizione.NOTECHIUSURA = NewPanel.ClosureNotesNewPanel
   
  Utente currentUser = QappCore.Loggeduser
  boolean closeResult = this.Disposizione.closeMultipleDisposizione(currentUser, normalMode)
   
  this.close(closeResult)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TipoDisposizioneSelection.showForm(
  int idClasse      // 
  IDForm callerForm // 
)
{
  this.CallerForm = callerForm
  IDCollection tipoDisposizioni of TipoDisposizione = TipoDisposizione.listActiveForClasse(idClasse)
   
  TipoDisposizione.setCollection(tipoDisposizioni, true)
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelloEventoDefinizioneSubform.handleLoadMessage(
  IDDocument Doc // 
)
{
  if (ModelloEvento.isMyInstance(Doc))
  {
    ModelloEvento me = (ModelloEvento)Doc
    int noteHtmlPropertyIndex = me.getPropertyIndex("DESCEVENHTML", true, true, true, true)
    HTMLEditorConfiguration htmlec = HTMLEditorConfiguration.create(500, me, noteHtmlPropertyIndex, false)
    IDForm htmlEditorSubform = getDevextremeSubformInstance(html)
    ModelloEventoDefinizione.LabeldescrEvento.setLabelSubForm(htmlEditorSubform, ...)
    htmlEditorSubform.sendMessage(configuration, htmlec, ...)
     
    ModelloEventoDefinizione.setDocument(me, true)
    me.updated = false
     
    // check parameters to manage evento da web options
    this.handleEventoDaWebPanelOptions()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelloEventoDefinizioneSubform.handleEventoDaWebPanelOptions()
{
  ModelloEvento me = ModelloEventoDefinizione.document
   
  if (me.WORKFLOWTYPE == Normal)
  {
    int disposizioniWithoutExecutorCount = 0
    for each ModelloEventoDisposizione med in me.DisposizioniModello
    {
      if (med.ModelloEventoDisposizioniExecutorIDForDecodingInUI == "")
         disposizioniWithoutExecutorCount = disposizioniWithoutExecutorCount + 1
    }
     
    if (me.STARTFROMQMOBILE == Yes && disposizioniWithoutExecutorCount > 0)
    {
      UIBusinessLogic.messageBox("Per i modelli non a comportamento Workflow è possibile configurare un link solo se non ci sono disposizioni o se tutte le disposizioni hanno un esecutore.")
      me.STARTFROMQMOBILE = No
    }
  }
   
  if (me.SUPPORTPUBLICINFO == Yes)
  {
    if (me.STARTFROMQMOBILE == No)
    {
      UIBusinessLogic.messageBox("Puoi abilitare questa opzione solo se è 'Avviabile da link'")
      me.SUPPORTPUBLICINFO = No
    }
  }
   
  if (me.STARTFROMQMOBILE == Yes)
  {
    ModelloEventoDefinizione.ButtonConfigura.setVisible(true)
  }
  else 
  {
    ModelloEventoDefinizione.ButtonConfigura.setVisible(false)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelloEventoDefinizioneSubform.handleButtonConfiguraEventoDaWeb()
{
  ModelloEvento me = ModelloEventoDefinizione.document
   
  // to open the web link, we need to have the modello evento saved to db
  if (me.isModified(...))
  {
    if (me.validate(...))
    {
      CommonConfirmationFrom ccf = CommonConfirmationFrom.newInstance(Modal, ...)
      ccf.ShowForm("Per configurare l'evento da web, il modello evento deve prima essere salvato. Salvo su DB?", me, "", Save, "Salva per configurare", "SALVA", "Annulla", this, "SAVE_OPENEVENTOWEB")
    }
    else 
    {
      UIBusinessLogic.messageBox("Alcuni campi non sono compilati correttamente.")
    }
  }
  else 
  {
    this.OpenEventoDaWebConfigurationPage()
  }
   
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelloEventoDefinizioneSubform.OpenEventoDaWebConfigurationPage()
{
  ModelloEvento me = ModelloEventoDefinizione.document
   
  UIBusinessLogic.userRole = Administrator
   
  TokenUrlConfiguration tuc = TokenUrlConfiguration.newInstance(...)
  tuc.ShowForm(me.IDTEMPLATEEVENTO, 0, false)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelloEventoDefinizioneSubform.Buttontoggleaitemp()
{
  boolean pageIsVisible = ModelloEventoDefinizione.AIpromptspage.pageVisible()
  ModelloEventoDefinizione.AIpromptspage.setPageVisible(!(pageIsVisible))
}


// ──────────────────────────────────



// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event ModelloEventoDefinizioneSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "SAVE_OPENEVENTOWEB":
      ModelloEvento me = (ModelloEvento)Doc
      if (me.validate(0, 999))
      {
         boolean hasBeenModelloEventoSavedCorrectly = me.saveToDB(...)
         if (hasBeenModelloEventoSavedCorrectly)
         {
           this.OpenEventoDaWebConfigurationPage()
         }
      }
    break
    case "LOAD":
      this.handleLoadMessage(Doc)
    break
  }
}


// ──────────────────────────────────

// *********************************************************************
// Event raised after saving the data for an edited row to the database.
// *********************************************************************
event ModelloEventoDefinizioneSubform.ModelloEventoDefinizione.AfterUpdate()
{
  this.handleEventoDaWebPanelOptions()
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event OpzioniModelliSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
   
  UIBusinessLogic.DTTLogMessage("OpzioniModelli OnSendMessage: " + Message, 111, DTTWarning)
   
  switch (Message)
  {
    case "LOAD":
      this.handleLoadMessage(Message, Doc)
    break
    case "NEW_REFERENCE_TYPE_SELECTED":
      ReferenceType rt = (ReferenceType)Doc
      if (!(ReferenceTypeAlreadyExists(rt)))
      {
         ModelloEventoRiferimento mer = ModelloEventoRiferimento.create(this.ModelloEvento, rt, ...)
         IDCollection mers of ModelloEventoRiferimento = ModelloEventoReferences.collection
          
         UIBusinessLogic.DTTLogMessage(mer.saveToXML(null, null, 0, JSON, ...), ...)
          
         mers.add(mer)
      }
      else 
      {
         UIBusinessLogic.messageBox("Il tipo riferimento esiste.")
      }
    break
    case "DELETE_ROW":
      this.DeleteModelloEventoRiferimento()
    break
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event OpzioniModelliSubform.Load()
{
//  GlobalPanelOperations.enableOnlyBasicCommands(ModelloEventoReferences.IDPanel(), ...)
  ModelloEventoReferences.setCommandEnabled(Duplicate, false)
  ModelloEventoReferences.setCommandEnabled(Insert, false)
  ModelloEventoReferences.setCommandEnabled(Delete, false)
  ModelloEventoReferences.setCommandEnabled(Refresh, false)
  ModelloEventoReferences.setCommandEnabled(Update, false)
  ModelloEventoReferences.setCommandEnabled(SaveBlob, false)
  ModelloEventoReferences.setCommandEnabled(Cancel, false)
  ModelloEventoReferences.setCommandEnabled(Navigate, false)
   
  ModelloEventoReferences.collapsable = false
  ModelliEventiCDSections.collapsable = false
   
  ModelloEventoReferences.showToolbar(true)
   
//  // uncomment this to reenable centralized code
//  IDPanel idp = ModelloEventoReferences.IDPanel()
//  PanelRowButtonController prbc = PanelRowButtonController.create(idp, this.IDForm())
//  prbc.setup(left, ..., hide)
}


// ──────────────────────────────────

// ***********************************************************
// Event raised by the panel before executing a panel command.
// ***********************************************************
event OpzioniModelliSubform.ModelloEventoReferences.OnCommand(
  int:panelCommands Command // An integer representing the command that is about to be run. It should be compared with the values in the PanelCommands value list.
  inout boolean Cancel      // Can be set to True to cancel the command.
  boolean UserOperation     // A boolean value that is True if the event was raised because the user clicked a panel toolbar button, and False if the event was raised because one of the panel's procedures wa...
)
{
  if (Command == Insert)
  {
    this.AddModelloEventoRiferimentoFromPopupMenu()
  }
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event OpzioniModelliSubform.ModelloEventoReferences.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  IDDocument selectedDocument = null
   
  if (!(isNull(Row)) && Row >= 0)
  {
    IDCollection coll of ModelloEventoRiferimento = new()
    coll.addAll(ModelloEventoReferences.collection, false)
     
    if (coll && coll.count() > 0)
    {
      ModelloEventoRiferimento mer = (ModelloEventoRiferimento)coll.getDirect(Row + 1)
       
      if (mer != null && mer.IDTipoRiferimento > 0)
      {
         selectedDocument = (IDDocument)mer
      }
    }
  }
   
  if (Button == Right)
  {
    Addreference.visible = true
    Deletereference.visible = false
     
    if (selectedDocument != null)
      Deletereference.visible = true
     
    ReferenceRightClickCommandSet.caption = "Opzioni"
    ReferenceRightClickCommandSet.openPopupXY(XB, YB)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void OpzioniModelliSubform.handleLoadMessage(
  string Message // 
  IDDocument Doc // 
)
{
  if (Message == "LOAD" and ModelloEvento.isMyInstance(Doc))
  {
    ModelloEvento me = (ModelloEvento)Doc
    this.ModelloEvento = me
     
    if (!(me.ModelloEventoCDSections.loaded))
    {
      me.loadModelloEventoCDSections(...)
    }
    if (!(me.ModelloEventoRiferimenti.loaded))
    {
      me.loadModelloEventoRiferimenti(...)
    }
     
    for each ModelloEventoCDSection mecds in me.ModelloEventoCDSections
    {
      mecds.setModelloEvento(me)
    }
     
    ModelloEventoReferences.setCollection(me.ModelloEventoRiferimenti, true)
    ModelliEventiCDSections.setCollection(me.ModelloEventoCDSections, true)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean OpzioniModelliSubform.ReferenceTypeAlreadyExists(
  ReferenceType refType // 
)
{
  boolean refTypeAlreadyExistsInCollection = false
  IDCollection mers of ModelloEventoRiferimento = ModelloEventoReferences.collection
  for each ModelloEventoRiferimento mer in mers
  {
    if (mer.IDTipoRiferimento == refType.IDTipoRiferimento)
    {
      refTypeAlreadyExistsInCollection = true
      break 
    }
  }
  return refTypeAlreadyExistsInCollection
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void OpzioniModelliSubform.DeleteModelloEventoRiferimento()
{
  ModelloEventoRiferimento mer = ModelloEventoReferences.document
  if (mer)
  {
    ModelloEventoReferences.deleteRow()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void OpzioniModelliSubform.AddModelloEventoRiferimentoFromPopupMenu()
{
  UIBusinessLogic.ReferenceTypeMenuController.openPopupMenu(this.ModelloEvento, this.IDForm(), Addreference.getRD3ID())
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void OpzioniModelliSubform.NewReferenceModelloEventoRiferimentoFromToolbar()
{
  UIBusinessLogic.ReferenceTypeMenuController.openPopupMenu(this.ModelloEvento, this.IDForm(), newReference.getRD3ID())
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelliDisposizioniSubform.handleLoadMessage(
  IDDocument Doc // 
)
{
  if (ModelloEvento.isMyInstance(Doc))
  {
    ModelloEvento me = (ModelloEvento)Doc
    if (me.DisposizioniModello.count() == 0)
    {
      me.loadDisposizioniModello(...)
    }
    this.ModelloEvento = me
    ModelloDisposizioniPanel.setCollection(this.ModelloEvento.DisposizioniModello, true)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelliDisposizioniSubform.Add()
{
  ModelloEventoDisposizione med = ModelloEventoDisposizione.create(this.ModelloEvento)
  ModelloEvento.DisposizioniModello.add(med)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelliDisposizioniSubform.Delete()
{
  ModelloEventoDisposizione med = ModelloDisposizioniPanel.document
  if (med != null)
  {
    med.deleted = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelliDisposizioniSubform.ButtonMoveUp()
{
  ModelloEventoDisposizione med = ModelloDisposizioniPanel.document
  if (med)
  {
    if (med.canMoveUp())
    {
      med.moveUp()
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelliDisposizioniSubform.ButtonMoveDown()
{
  ModelloEventoDisposizione med = ModelloDisposizioniPanel.document
  if (med)
  {
    if (med.canMoveDown())
    {
      med.moveDown()
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelliDisposizioniSubform.openRecipients()
{
  ModelloEventoDisposizione med = ModelloDisposizioniPanel.document
  if (med)
  {
    NotificationRecipients.showForm(med)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ModelliDisposizioniSubform.OpenCheckList()
{
  ModelloEventoDisposizione med = ModelloDisposizioniPanel.document
  if (med)
  {
    ModelloEventoChecklist mec = ModelloEventoChecklist.newInstance(Modal, ...)
    mec.ShowForm(med)
  }
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
private void ModelliDisposizioniSubform.OpenNotifyToOtherChooserModal()
{
  LookupHelper lh = LookupHelper.create(this, Personale, true, ..., "NOTIFYOTHERS")
  lh.displayLookup()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelliDisposizioniSubform.Close()
{
  QuickViewDisposizioneDetail.visible = false
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event ModelliDisposizioniSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "LOAD":
      this.handleLoadMessage(Doc)
    break
    case "DELETE_ROW":
      this.Delete()
    break
  }
   
  if (!(isNull(Par3)))
  {
    switch (Par3)
    {
      case "NOTIFYOTHERS":
         string selectedResults = ""
          
         IDCollection selectedContatti of Contatto = new()
         IDCollection selectedPersonale of Personale = new()
          
         SearchResult sr1 = (SearchResult)Doc
         if (Message == "setLookupResults")
         {
           SearchResult sr = (SearchResult)Doc
           if (sr)
           {
             // contatto
             if (Par4 == "contatti")
             {
                IDCollection selectedContattiIDsInSearch of IntDataType = sr1.getDataTypeCollection()
                for each IntDataType idtc in selectedContattiIDsInSearch
                {
                  Contatto c = Contatto.get(idtc.IntegerValue)
                  selectedContatti.add(c)
                }
                 
                for each Contatto c in selectedContatti
                {
                  if (selectedResults == "")
                    selectedResults = c.EMAIL
                  else 
                    selectedResults = selectedResults + "," + c.EMAIL
                }
             }
             else  // personale
             {
                IDCollection selectedPersonaleIDsInSearch of IntDataType = sr.getDataTypeCollection()
                for each IntDataType idtc in selectedPersonaleIDsInSearch
                {
                  Personale p = Personale.getFromDB(idtc.IntegerValue, ...)
                  selectedPersonale.add(p)
                }
                 
                for each Personale p in selectedPersonale
                {
                  if (selectedResults == "")
                    selectedResults = p.EMAIL
                  else 
                    selectedResults = selectedResults + "," + p.EMAIL
                }
             }
           }
         }
          
         if (selectedResults == "")
         {
           ModelloDisposizioniQuickviewPanel.NOTIFYOTHERS = "N"
         }
         else 
         {
           DevTools.ToBeReviewed("I dati sono salvati in un altro formato.. non mail separate da virgola")
            
           UIBusinessLogic.DTTLogMessage("Need to fix the output format of subjects to be notified", ..., DTTWarning)
            
           ModelloDisposizioniQuickviewPanel.NOTIFYOTHERS = selectedResults
         }
      break
    }
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event ModelliDisposizioniSubform.Load()
{
  ModelloDisposizioniPanel.collapsed = false
  ModelloDisposizioniPanel.collapsable = false
  ModelloDisposizioniPanel.setCommandEnabled(Refresh, false)
  ModelloDisposizioniPanel.setCommandEnabled(Duplicate, false)
  ModelloDisposizioniPanel.setCommandEnabled(Insert, false)
  ModelloDisposizioniPanel.setCommandEnabled(Delete, false)
  ModelloDisposizioniPanel.setCommandEnabled(SaveBlob, false)
  ModelloDisposizioniPanel.setErrorMode(true, true, true, true)
  ModelloDisposizioniQuickviewPanel.collapsable = false
   
  IDPanel idp = ModelloDisposizioniPanel.IDPanel()
   
  PanelRowButtonController prbc = PanelRowButtonController.create(idp, this.IDForm())
  prbc.setup(left, ..., right, ModelliDisposizioniRowCommandset.IDCommand())
}


// ──────────────────────────────────

// *********************************************************************************
// Event raised by the form object in web applications when a modal window is closed
// *********************************************************************************
event ModelliDisposizioniSubform.EndModal(
  int LookupForm       // An integer that identifies the modal form that was just closed, using the Me function of the form object to make the comparison.
  boolean Result       // True if the user confirmed the choice, closing the model form using the confirmation button on the title bar; otherwise False. The form can also be closed using the form object's Cl...
  inout boolean Cancel // If set to True, any subsequent automatic processing will be canceled. In this case, the framework will not attempt to automatically transfer the data from the modal form to the call...
)
{
  if (Result)
  {
    if (LookupForm == ModelloEventoChecklist.me())
    {
      ModelloEventoDisposizione med = ModelloDisposizioniPanel.document
      if (med)
      {
         med.updateStatoCKL()
      }
    }
    if (LookupForm == NotificationRecipients.me())
    {
      ModelloEventoDisposizione med = ModelloDisposizioniPanel.document
      if (med)
      {
         med.NOTIFYOTHERS = med.computeNotifyOthersText()
      }
    }
  }
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event ModelliDisposizioniSubform.ModelloDisposizioniPanel.OnChangeRow()
{
  // get current selected item
  this.SelectedDisposizione = ModelloDisposizioniPanel.document
   
  // setup popupmenu button visibility
  if (this.SelectedDisposizione)
  {
    Moveup.visible = this.SelectedDisposizione.canMoveUp()
    MoveDown.visible = this.SelectedDisposizione.canMoveDown()
  }
  Delete.visible = (this.SelectedDisposizione != null)
   
  // update the detail panel
  if (this.SelectedDisposizione != null)
  {
    ModelloDisposizioniQuickviewPanel.visible = true
    ModelloDisposizioniQuickviewPanel.document = this.SelectedDisposizione
  }
  else 
  {
    ModelloDisposizioniQuickviewPanel.visible = false
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event ModelliDisposizioniSubform.ModelloDisposizioniPanel.OnDynamicProperties()
{
  // get the disposizione and update the statockl field
  ModelloEventoDisposizione med = ModelloDisposizioniPanel.document
  if (med)
  {
    ModelloDisposizioniPanel.CHKBTN.CSSClass = med.GetChecklistCssClassForIcon()
    ModelloDisposizioniPanel.CHKBTN.text = med.GetChecklistTextIconForIcon()
     
    ModelloDisposizioniQuickviewPanel.CHKBTN.CSSClass = med.GetChecklistCssClassForIcon()
    ModelloDisposizioniQuickviewPanel.CHKBTN.text = med.GetChecklistTextIconForIcon()
     
  }
   
   
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event ModelliDisposizioniSubform.ModelloDisposizioniQuickviewPanel.OnDynamicProperties()
{
  if (this.SelectedDisposizione)
  {
    // set the color of the button icon with css class
     
  }
   
   
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void LinkedEventi.handleLoadMessage(
  string Message // 
  IDDocument Doc // 
)
{
  if (Message == "LOAD" and ModelloEvento.isMyInstance(Doc))
  {
    ModelloEvento me = (ModelloEvento)Doc
    IDCollection linkedEventi of Evento = me.getLinkedEventi()
    Eventi.setCollection(linkedEventi, true)
     
     
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void LinkedEventi.open()
{
  Evento e = Eventi.document
  if (e)
  {
//    EventiDetail.formShow(e, this, false)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void InstructionsSubform.handleLoadMessage(
  string Message // 
  IDDocument Doc // 
)
{
  if (Message == "LOAD")
  {
    int htmlIndexProperty = 0
    boolean readOnly = false
    ModelloEvento sourceModelloEvento = new()
     
    if (ModelloEvento.isMyInstance(Doc))
    {
      sourceModelloEvento = (ModelloEvento)Doc
      htmlIndexProperty = sourceModelloEvento.getPropertyIndex("INSTRUCTHTML", true, true, true, true)
      readOnly = false
    }
    if (Evento.isMyInstance(Doc))
    {
      Evento e = (Evento)Doc
      sourceModelloEvento = ModelloEvento.getFromDB(e.IDTEMPLATEEVENTO, ...)
      htmlIndexProperty = sourceModelloEvento.getPropertyIndex("INSTRUCTHTML", true, true, true, true)
       
      e.updated = false
      readOnly = true
    }
    sourceModelloEvento.updated = false
     
    HTMLEditorConfiguration htmlec = HTMLEditorConfiguration.create(500, sourceModelloEvento, htmlIndexProperty, readOnly)
    IDForm htmlEditorSubform = getDevextremeSubformInstance(html)
    NewPanel.LabelhtmleditorContainer.setLabelSubForm(htmlEditorSubform, ...)
    htmlEditorSubform.sendMessage(configuration, htmlec, ...)
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event InstructionsSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  this.handleLoadMessage(Message, Doc)
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event NotificationRecipients.NotificationRecipeint.OnChangeRow()
{
  Ntfrecipient ntf = NotificationRecipeint.document
  if (ntf)
  {
    NotificationRecipeint.EMAIL.setEnabled(ntf.RECIPIENTTYPE == Others)
  }
}


// ──────────────────────────────────

// ********************************************
// Event raised by the form before it is closed
// ********************************************
event NotificationRecipients.Unload(
  inout int Cancel // If set to True, closure of the form is canceled.
  boolean Confirm  // Represents the user's selection for closing modal forms. True if the user confirms their choice, otherwise False.
)
{
  IDCollection recipients of Ntfrecipient = NotificationRecipeint.collection
  if (Confirm)
  {
    boolean isValidNtf = true
     
    for each Ntfrecipient ntf in recipients
    {
      isValidNtf = ntf.validate(...)
      if (!(isValidNtf))
      {
         break 
      }
    }
    if (!(isValidNtf))
    {
      Cancel = true
      DevTools.ToBeReviewed("since property errors are not displayed on panel we show a message")
      UIBusinessLogic.messageBox("Ogni destinatario deve avere un indirizzo email")
    }
  }
  else 
  {
    recipients.restoreOriginal()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event NotificationRecipients.Load()
{
  NotificationRecipeint.caption = ""
  NotificationRecipeint.collapsable = false
  NotificationRecipeint.collapsed = false
   
  NotificationRecipeint.setErrorMode(true, true, true, true)
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event NotificationRecipients.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "setLookupResults":
      if (this.NewlyAddedRecipient != null)
      {
         string recievedIdAsString = Par1
         string recievedDescription = Par2
         boolean isContatto = Par4 == "contatti"
          
         // contatto
         if (isContatto)
         {
           Contatto c = (Contatto)Doc
           this.NewlyAddedRecipient.RECPIENTVALUE = recievedIdAsString
           this.NewlyAddedRecipient.Recipient = recievedDescription
           this.NewlyAddedRecipient.EMAIL = c.EMAIL
         }
         else 
         {
           // personale
           MainModule mm = (MainModule)Doc
           int:kordapp recievedKordApp = mm.getKordApp()
           if (recievedKordApp == Personale)
           {
             Personale personale = (Personale)mm
             this.NewlyAddedRecipient.RECPIENTVALUE = recievedIdAsString
             this.NewlyAddedRecipient.Recipient = recievedDescription
             this.NewlyAddedRecipient.EMAIL = personale.EMAIL
              
           }
         }
      }
    break
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void NotificationRecipients.showForm(
  ModelloEventoDisposizione disposizione // Write a comment for this parameter or press backspace to delete this comment
)
{
  this.ModelloDisposizione = disposizione
  NotificationRecipeint.setCollection(disposizione.NTFRECIPIENTS, ...)
  this.show(Modal)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void NotificationRecipients.AddPersonale()
{
  this.addRecipient(Personale)
  LookupHelper lh = LookupHelper.create(this, Personale, false, null, ...)
  lh.displayLookup()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void NotificationRecipients.addContatto()
{
  this.addRecipient(Contact)
  LookupHelper lh = LookupHelper.create(this, ClientiFornitori, false, ..., Contatto.className(...))
  lh.displayLookup()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void NotificationRecipients.AddAltre()
{
  this.addRecipient(Others)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void NotificationRecipients.Elimina()
{
  NotificationRecipeint.deleteRow()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void NotificationRecipients.addRecipient(
  string:NTFRECIPIENTSTypes recipientType // 
)
{
  IDCollection recipients of Ntfrecipient = NotificationRecipeint.collection
  int mainId = this.ModelloDisposizione.IDTEMPLATEEVENTO
  int detailID = this.ModelloDisposizione.IDTEMPLATTIVITA
  boolean isFunction = if(this.ModelloDisposizione.ISFUNCTION == Yes, true, false)
  Ntfrecipient recipient = Ntfrecipient.create(recipientType, ModelliEventi, mainId, detailID, isFunction)
  recipients.add(recipient)
  this.NewlyAddedRecipient = recipient
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event ModelloEventoChecklist.Load()
{
  ModelloEventoDomande.caption = ""
  ModelloEventoDomande.collapsable = false
  ModelloEventoDomande.collapsed = false
  ModelloEventoDomande.setErrorMode(Message, Message, Message, Message)
   
  IDPanel idp = ModelloEventoDomande.IDPanel()
   
  PanelRowButtonController prbc = PanelRowButtonController.create(idp, IDForm())
  prbc.setup(left, ..., right, ChecklistCommandset.IDCommand())
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event ModelloEventoChecklist.ModelloEventoDomande.OnChangeRow()
{
  ChecklistItem templateItems = ModelloEventoDomande.document
   
  if (templateItems)
  {
    MoveUp.visible = this.ChecklistTemplate.CanMoveUpItem(templateItems)
    MoveDown.visible = this.ChecklistTemplate.CanMoveDownItem(templateItems)
    Delete.visible = true
  }
  else 
  {
    MoveUp.visible = false
    MoveDown.visible = false
    Delete.visible = false
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelloEventoChecklist.Add()
{
  this.ChecklistTemplate.AddChecklistItem()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelloEventoChecklist.Delete()
{
  if (ModelloEventoDomande.document)
  {
    ChecklistItem ci = ModelloEventoDomande.document
    this.ChecklistTemplate.removeChecklistItem(ci)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelloEventoChecklist.MoveUp()
{
  ChecklistItem checklistTemplate = ModelloEventoDomande.document
   
  if (checklistTemplate)
  {
    this.ChecklistTemplate.moveUpItem(checklistTemplate)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelloEventoChecklist.MoveDown()
{
  ChecklistItem checklistTemplateItem = ModelloEventoDomande.document
   
  if (checklistTemplateItem)
  {
    this.ChecklistTemplate.moveDownItem(checklistTemplateItem)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelloEventoChecklist.ShowForm(
  ModelloEventoDisposizione med // 
)
{
  this.caption = formatMessage("|1 - Checklist", med.DESCRATTIVITA, ...)
   
  this.ChecklistTemplate = med.getChecklist()
   
  if (this.ChecklistTemplate == null || ChecklistTemplate.ChecklistInstanceItemCollection == null || this.ChecklistTemplate.ChecklistTemplateType <= 0)
    UIBusinessLogic.DTTLogMessage("checklistTemplate is null", ..., DTTError)
   
  ModelloEventoDomande.setCollection(this.ChecklistTemplate.ChecklistInstanceItemCollection, true)
   
  this.show(Modal)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ModelloEventoChecklist.Confirm()
{
  boolean validChecklist = this.ChecklistTemplate.validate(...)
  if (validChecklist)
  {
    this.close(true)
  }
  else 
  {
    ModelloEventoDomande.showDocErrors(...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FunzioneDefinizioneSubform.HandleLoadMessage(
  string message // 
  IDDocument doc // 
)
{
  if (message == "LOAD" and Funzione.isMyInstance(doc))
  {
    Funzione f = (Funzione)doc
     
    FunzioneDefinizionePanel.setDocument(f, true)
     
    f.updated = false
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event FunzioneDefinizioneSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  this.HandleLoadMessage(Message, Doc)
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event FunzioneDefinizioneSubform.FunzioneDefinizionePanel.OnDynamicProperties()
{
  int indecolor = Tools.DxcolorToInde(FunzioneDefinizionePanel.COLORE)
  FunzioneDefinizionePanel.COLORE.backgroundColor = indecolor
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FunzioneNominativiSubform.HandleLoadMessage(
  string message // Write a comment for this parameter or press backspace to delete this comment
  IDDocument doc // 
)
{
  if (message == "LOAD" and Funzione.isMyInstance(doc))
  {
    Funzione f = (Funzione)doc
     
    f.loadFunzioneMsqPersFunzioniColl()
     
    NominativiList.setCollection(f.MSQPERSFUNZIONI, true)
    this.IDFUNZIONE = f.IDFUNZIONE
     
    f.updated = false
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FunzioneNominativiSubform.Delete()
{
  NominativiList.deleteRow()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FunzioneNominativiSubform.AddPersonaleToCollection(
  IDCollection personale of Personale // 
)
{
  if (this.IDFUNZIONE == 0)
  {
    UIBusinessLogic.DTTLogMessage("ID Funzione not identified. Can't add nominativo", ..., DTTError)
  }
   
  IDCollection nominativi of FunzioneMembers = NominativiList.collection
   
  for each Personale p in personale
  {
    FunzioneMembers fm = FunzioneMembers.create(p.IDDIPENDENTE, this.IDFUNZIONE)
     
    nominativi.add(fm)
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event FunzioneNominativiSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "setLookupResults")
  {
    SearchResult res = (SearchResult)Doc
    if (res)
    {
      // contatto
      if (Par4 == "contatti")
      {
         UIBusinessLogic.DTTLogMessage("Can't add contatti to FUNZIONI", ..., DTTError)
          
         UIBusinessLogic.messageBox("Non posso aggiungere un contatto")
//         IDCollection selectedContatti of IntDataType = res.getDataTypeCollection()
//         IDCollection contattiToAdd of Contatto = new()
          
//         for each IntDataType idt in selectedContatti
//         {
//           Contatto c = Contatto.get(idt.IntegerValue)
//           contattiToAdd.add(c)
//         }
          
         // add to result collection  TODO
          
      }
      else 
      {
         IDCollection selectedPersonale of IntDataType = res.getDataTypeCollection()
         IDCollection personaleToAdd of Personale = new()
          
         for each IntDataType idt in selectedPersonale
         {
           Personale p = Personale.getFromDB(idt.IntegerValue, ...)
           personaleToAdd.add(p)
         }
          
         // add to result collection
         this.AddPersonaleToCollection(personaleToAdd)
      }
    }
  }
  else 
  {
    this.HandleLoadMessage(Message, Doc)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void FunzioneNoteSubform.HandleLoadMessage(
  string message // Write a comment for this parameter or press backspace to delete this comment
  IDDocument doc // 
)
{
  if (message == "LOAD" and Funzione.isMyInstance(doc))
  {
    Funzione f = (Funzione)doc
     
    FunzioneNote.setDocument(f, true)
    f.updated = false
  }
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event FunzioneNoteSubform.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  this.HandleLoadMessage(Message, Doc)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.Save()
{
  try 
  {
    WkfStep step = this.WkfStep
     
    // fix NOTIFICA field null -> to this field is assigned the domain YES/NO.. so null is not valid. Set N as default
    if (isNull(step.NOTIFICA))
      step.NOTIFICA = No
    Diagram d = this.DiagramHandler.GetDiagram()
     
    boolean isStepValid = d.ValidateStep(step, ...)
     
    if (isStepValid)
    {
      this.close(...)
       
      for each WkfResult wr in step.WKFRESULTS
      {
         this.DiagramHandler.UpdateFlowDescriptionFromWkfResultUpdate(wr.IDRESULT)
      }
       
      this.DiagramHandler.updateStep(step)
       
      this.ParentForm.sendMessage("UNLOCK_ADD_STEP_BTN", ...)
    }
    else 
    {
      // get errors of all the properties
       
      string errorMessage = d.GetStepErrors(step)
       
      if (errorMessage != "")
      {
         UIBusinessLogic.messageBox(errorMessage)
      }
    }
  }
  catch 
  {
    UIBusinessLogic.DTTLogMessage("Workflow step UPDATE: " + errorMessage(), errorNumber(), DTTError)
    UIBusinessLogic.messageBox("Errore salvataggio dati!")
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void WKFStepDetailForm.deleteDisposizioni()
{
   
  for each MultipleStepTemplateDisposizione mstd in WkfStep.Disposizioni
  {
    mstd.deleted = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.showForm(
  IDForm callerForm // Write a comment for this parameter or press backspace to delete this comment
)
{
  this.ParentForm = callerForm
  this.show(Modal)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.SetupStepDetailsFields()
{
  StepDetail.ButtonDisposizioni.setEnabled(false)
  StepDetail.DescriptionMultiSourceResponsible.setEnabled(false)
   
  if (StepDetail.MULTIPLEWkfStep == Yes)
  {
    StepDetail.ButtonDisposizioni.setEnabled(true)
  }
   
  if (StepDetail.EXECUTORTYPEWkfStep == Manuale)
  {
    StepDetail.DescriptionMultiSourceResponsible.setEnabled(true)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.SetupNotificationFields()
{
  Mailsender.NOTIFYADVANCEDAYS.setEnabled(false)
  Mailsender.NOTIFYDELAYSDAYS.setEnabled(false)
  Mailsender.NOTIFYDELAYSCONTINUEDAYS.setEnabled(false)
   
  if (Mailsender.NOTIFYINADVANCE == Yes)
  {
    Mailsender.NOTIFYADVANCEDAYS.setEnabled(true)
  }
   
  if (Mailsender.NOTIFYDELAYS == Yes)
  {
    Mailsender.NOTIFYDELAYSDAYS.setEnabled(true)
  }
   
  if (Mailsender.NOTIFYDELAYSCONTINUE == Yes)
  {
    Mailsender.NOTIFYDELAYSCONTINUEDAYS.setEnabled(true)
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.populateTipiAttivitaDropdown(
  int idClasse // 
)
{
  IDCollection tipi of TipoDisposizione = new()
  select into collection (tipi)
    set IDTIPOATTIVITA = IDTIPOATTIVITA
    set IDORIGINE = IDORIGINE
    set IDCLASSE = IDCLASSE
    set DESCRTIPOATTIVITA = DESCRTIPOATTIVITA
    set ATTIVO = ATTIVO
    set SEQUENZA = SEQUENZA
    set DESCRDEFAULT = DESCRDEFAULT
    set IDTEMPLATE = IDTEMPLATE
    set TEMPLATE = TEMPLATE
    set IDPARENTTEMPLATEREMOTE = IDPARENTTEMPLATEREMOTE
    set CHKLISTCOMPMANDATORY = CHKLISTCOMPMANDATORY
  from 
    TipiDisposizioni // master table
  where
    IDCLASSE = idClasse
   
  for each TipoDisposizione td in tipi
  {
    StepDetail.IDTIPOATTIVITA.addValueListItem(td.IDTIPOATTIVITA, td.DESCRTIPOATTIVITA, ...)
  }
   
  if (tipi.count() == 1)
  {
    tipi.moveFirst()
    TipoDisposizione td = (TipoDisposizione)tipi.getAt()
    StepDetail.IDTIPOATTIVITAWkfStep = td.IDTIPOATTIVITA
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.AddEsito()
{
  IDArray errorsArray = new()
  Diagram d = this.DiagramHandler.GetDiagram()
  d.addEsitoToStep(this.WkfStep, errorsArray)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.RemoveEsito()
{
  for each WkfResult esito in WkfStep.WKFRESULTS
  {
    if (esito.IDRESULT == this.CurrentSelectedWkfResultId)
    {
      IDArray errorsArray = new()
      Diagram d = this.DiagramHandler.GetDiagram()
      d.RemoveEsitoFromStep(this.WkfStep, esito, errorsArray)
       
      WkfStep ws = d.getStepFromDiagram(esito.IDSTEP)
       
      IDCollection stepFlows of WkfFlow = d.getFlowsOfSpecificStep(ws)
       
      for each WkfFlow wf1 in stepFlows
      {
         if (wf1.IDRESULT == esito.IDRESULT)
         {
           d.removeFlow(wf1, errorsArray)
           this.DiagramHandler.removeFlow(wf1)
         }
      }
       
      if (errorsArray.length() > 0)
      {
         UIBusinessLogic.messageBox("Errore: " + Tools.ArrayToString(errorsArray, "<br/>"))
      }
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.ClearCustomData()
{
  for each WkfResult wr in WkfStep.WKFRESULTS
  {
    if (wr.IDRESULT == this.CurrentSelectedWkfResultId)
    {
      wr.CdataWkfResultLinks.clear()
    }
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.ChecklistAdd()
{
  WkfStep.ChecklistTemplate.AddChecklistItem()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.ChecklistDelete()
{
  ChecklistItem currentItem = Checklist.document
   
  if (currentItem)
  {
    WkfStep.ChecklistTemplate.removeChecklistItem(currentItem)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.ChecklistMoveUp()
{
  ChecklistItem currentItem = Checklist.document
   
  if (currentItem)
  {
    WkfStep.ChecklistTemplate.moveUpItem(currentItem)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.ChecklistMoveDown()
{
  ChecklistItem currentItem = Checklist.document
   
  if (currentItem)
  {
    WkfStep.ChecklistTemplate.moveDownItem(currentItem)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.ClearAltreNotificheSelection()
{
  Mailsender.NOTIFYOTHERS = "N"
}


// ──────────────────────────────────

// ************************************************
// Open form to select other user/contact to notify
// ************************************************
public void WKFStepDetailForm.OpenNotifyOthersSelectionForm()
{
  LookupHelper lh = LookupHelper.create(this, Personale, true, ..., "NOTIFYOTHER")
  lh.displayLookup()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepDetailForm.retrieveIdClasseAndPopulateTipiAttivita()
{
  if (this.DiagramHandler)
  {
    ModelloEvento me = this.DiagramHandler.GetDiagramModelloEvento()
    if (me != null)
    {
      this.populateTipiAttivitaDropdown(me.IDCLASSE)
    }
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event WKFStepDetailForm.Load()
{
  EsitiDisposizione.collapsable = false
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event WKFStepDetailForm.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
   
  if (!(isNull(Par3)))
  {
    // Par3 is used to distinguish how is calling the lookup form
    switch (Par3)
    {
      case "NOTIFYOTHER":
         string selectedResults = ""
          
         IDCollection selectedContatti of Contatto = new()
         IDCollection selectedPersonale of Personale = new()
          
         SearchResult sr1 = (SearchResult)Doc
         if (Message == "setLookupResults")
         {
           SearchResult sr = (SearchResult)Doc
           if (sr)
           {
             // contatto
             if (Par4 == "contatti")
             {
                IDCollection selectedContattiIDsInSearch of IntDataType = sr1.getDataTypeCollection()
                for each IntDataType idtc in selectedContattiIDsInSearch
                {
                  Contatto c = Contatto.get(idtc.IntegerValue)
                  selectedContatti.add(c)
                }
                 
                for each Contatto c in selectedContatti
                {
                  if (selectedResults == "")
                    selectedResults = c.EMAIL
                  else 
                    selectedResults = selectedResults + "," + c.EMAIL
                }
             }
             else  // personale
             {
                IDCollection selectedPersonaleIDsInSearch of IntDataType = sr.getDataTypeCollection()
                for each IntDataType idtc in selectedPersonaleIDsInSearch
                {
                  Personale p = Personale.getFromDB(idtc.IntegerValue, ...)
                  selectedPersonale.add(p)
                }
                 
                for each Personale p in selectedPersonale
                {
                  if (selectedResults == "")
                    selectedResults = p.EMAIL
                  else 
                    selectedResults = selectedResults + "," + p.EMAIL
                }
             }
           }
         }
          
         // set result field: if no result selected, set "N" as No
         if (selectedResults == "")
         {
           Mailsender.NOTIFYOTHERS = "N"
         }
         else 
         {
           DevTools.ToBeReviewed("I dati sono salvati in un altro formato.. non mail separate da virgola")
            
           UIBusinessLogic.DTTLogMessage("Need to fix the output format of subjects to be notified", ..., DTTWarning)
            
           Mailsender.NOTIFYOTHERS = selectedResults
         }
      break
      default:
         UIBusinessLogic.DTTLogMessage("CASE NOT MANAGED", ..., DTTError)
      break
    }
  }
   
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event WKFStepDetailForm.Mailsender.OnDynamicProperties()
{
  this.SetupNotificationFields()
}


// ──────────────────────────────────

// *******************************************************************
// Event raised by the panel when a user changes the data in the panel
// *******************************************************************
event WKFStepDetailForm.Mailsender.OnUpdatingRow(
  int Column // An integer specifying which field triggered the event being executed. The Me property of the panel field should be used to perform comparisons.
  boolean FieldModified    // A boolean value specifying that the field has actually been modified, i.e., its value is different from that originally read from the database.
  boolean FieldWasModified // Since version 6.7.2900, this argument specifies whether the field has changed in the last browser transmission, and can therefore be used to determine which fields have actually...
  boolean RowWasModified   // This argument should not be used; it is present only for compatibility with older versions of Instant Developer.
  boolean Inserting        // A boolean value specifying whether the current row is being edited (false) or inserted (true).
  inout boolean Cancel     // Do not use this argument. To report an error condition, use the SetErrorText functions of the panel field or of the panel itself.
)
{
  this.SetupNotificationFields()
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event WKFStepDetailForm.StepDetail.OnDynamicProperties()
{
  this.SetupStepDetailsFields()
   
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event WKFStepDetailForm.StepDetail.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
   
  if (Column == StepDetail.MULTIPLE.me())
  {
     
    UIBusinessLogic.DTTLogMessage(this.WkfStep.MULTIPLE, 56565656, ...)
    UIBusinessLogic.DTTLogMessage(StepDetail.MULTIPLEWkfStep, 56565656, ...)
    UIBusinessLogic.DTTLogMessage(this.WkfStep.Disposizioni.count(), 56565656, ...)
    if (this.WkfStep.Disposizioni.count() > 0 and StepDetail.MULTIPLEWkfStep == No)
    {
      int i = UIBusinessLogic.messageConfirmEx("Le disposizioni dello step multiplo verranno eliminate, confermi?", "Si;No")
      if (i == null)
      {
         return 
      }
      UIBusinessLogic.DTTLogMessage(i, ..., DTTInfo)
      //  
      // se si
      if (i == 1)
      {
         UIBusinessLogic.DTTLogMessage("Clear Disposizioni collection", ..., DTTInfo)
          
         this.deleteDisposizioni()
          
      }
    }
     
     
  }
}


// ──────────────────────────────────

// ***********************************************************************
// Event raised by the panel when the data in the active panel row changes
// ***********************************************************************
event WKFStepDetailForm.Checklist.OnChangeRow()
{
  ChecklistItem current = Checklist.document
   
  ChecklistMoveDown.visible = false
  ChecklistMoveUp.visible = false
   
  if (current)
  {
    ChecklistMoveUp.visible = this.WkfStep.ChecklistTemplate.CanMoveUpItem(current)
    ChecklistMoveDown.visible = this.WkfStep.ChecklistTemplate.CanMoveDownItem(current)
  }
}


// ──────────────────────────────────

// **********************************************
// Raised by the panel when the user clicks on it
// **********************************************
event WKFStepDetailForm.EsitiDisposizione.OnMouseClick(
  int:mouseButtons Button // Specifies which mouse button has been pressed. Refer also to the MouseButtons value list
  int X                // X position in pixels relative to the panel in which the mouse was clicked
  int Y                // Y position in pixels relative to the panel in which the mouse was clicked
  int XB               // X position in pixels relative to the browser in which the mouse was clicked
  int YB               // Y position in pixels relative to the browser in which the mouse was clicked
  int Column           // Index of the field that was clicked (-1 if the click occurred outside the fields)
  int Row              // Row clicked, from 0 to VisibleRows -1. This is -1 if the click occurred outside the fields or on the caption of the column or field
  inout boolean Cancel // Can be set to True to prevent the default action associated with the click from being run, such as execution of the field activation object.
)
{
  this.CurrentSelectedWkfResultId = 0
   
  if (!(isNull(Row)) && Row >= 0)
  {
    IDCollection coll of WkfResult = new()
    coll.addAll(EsitiDisposizione.collection, false)
     
    if (coll && coll.count() > 0)
    {
      WkfResult selected = (WkfResult)coll.getDirect(Row + 1)
       
      if (selected && selected.IDRESULT > 0)
      {
         UIBusinessLogic.DTTLogMessage("Current selected Wkf result id" + toString(selected.IDRESULT), 66, DTTWarning)
         this.CurrentSelectedWkfResultId = selected.IDRESULT
      }
    }
  }
   
  if (Button == Right)
  {
    AddEsito.visible = true
    AssignCustomData.visible = false
    RemoveEsito.visible = false
     
    if (this.CurrentSelectedWkfResultId > 0)
    {
      AssignCustomData.visible = true
      RemoveEsito.visible = true
    }
     
    EventiDisposizioniRightClickMenu.caption = "Opzioni Esiti"
    EventiDisposizioniRightClickMenu.openPopupXY(XB, YB)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepMultipleDisposizioneForm.AddEntry()
{
   
  MultipleStepTemplateDisposizione disp = MultipleStepTemplateDisposizione.create(this.ModelloEvento, this.Step, ...)
   
  Step.Disposizioni.add(disp)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFStepMultipleDisposizioneForm.showForm(
  WkfStep step                // 
  ModelloEvento modelloEvento // 
)
{
  this.Step = step
  this.ModelloEvento = modelloEvento
   
  WKFStepDisposizioniPanel.setCollection(step.Disposizioni, true)
  this.show(Modal)
}


// ──────────────────────────────────



// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event WKFStepMultipleDisposizioneForm.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "DELETE_ROW")
  {
    this.delete()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event WKFStepMultipleDisposizioneForm.Load()
{
  WKFStepDisposizioniPanel.collapsable = false
  WKFStepDisposizioniPanel.setCommandEnabled(Refresh, false)
  WKFStepDisposizioniPanel.setCommandEnabled(Duplicate, false)
  WKFStepDisposizioniPanel.setCommandEnabled(Insert, false)
  WKFStepDisposizioniPanel.setCommandEnabled(Delete, false)
  WKFStepDisposizioniPanel.setCommandEnabled(Cancel, false)
  WKFStepDisposizioniPanel.setCommandEnabled(Update, false)
//  WKFStepDisposizioniPanel.setErrorMode(Message, Message, Message, Message)
   
  IDPanel idp = WKFStepDisposizioniPanel.IDPanel()
   
  PanelRowButtonController prbc = PanelRowButtonController.create(idp, this.IDForm())
  prbc.setup(left, ..., right, WkfStepMultipleDisposizioneRowCommandset.IDCommand())
}


// ──────────────────────────────────

// **********************************************
// Load custom data for this workflow step result
// **********************************************
public void WKFStepEsitiCustomDataForm.LoadCustomDataForWkfResultId()
{
  this.WKFResult = this.Diagram.getSpecificResultInStep(this.Step, this.WkfResultId)
   
  IDCollection coll of CdataWkfResultDisplayUIClass = new()
  coll = CdataWkfResultDisplayUIClass.getModelloEventoWkfResultCDataCollection(this.ModelloEvento, this.WKFResult)
   
  // set the flag of the state of
  for each CdataWkfResultLink link in WKFResult.CdataWkfResultLinks
  {
    for each CdataWkfResultDisplayUIClass ui in coll
    {
      if (link.IDRESULTCD == ui.IDRESULTCD and link.IDRESULT == ui.IDRESULT and link.IDCDATAFLD == ui.IDCDATAFLD)
      {
         if (link.ISREADONLY == Yes)
           ui.ISREADONLY = true
          
         if (link.OBBLIGATORIO == Yes)
           ui.MANDATORY = true
          
         if (link.IDCDATAFLD > 0)
           ui.SHOW = true
      }
    }
  }
   
  CdataPanel.setCollection(coll, false)
}


// ──────────────────────────────────

// ******************************
// close the modal without saving
// ******************************
public void WKFStepEsitiCustomDataForm.DismissAndClose()
{
  this.close(false)
}


// ──────────────────────────────────

// *********************************
// save the data and close the modal
// *********************************
public void WKFStepEsitiCustomDataForm.SaveAndClose()
{
  IDCollection cdataResults of CdataWkfResultDisplayUIClass = CdataPanel.collection
   
  this.WKFResult.CdataWkfResultLinks = WorkflowLogic.cdataLinksUpdateManager(cdataResults, this.WKFResult)
   
  this.close(true)
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void WKFStepEsitiCustomDataForm.ShowForm(
  Diagram diagram             // 
  WkfStep step                // 
  ModelloEvento modelloEvento // 
  int wkfResultId             // 
)
{
  this.WkfResultId = wkfResultId
  this.Diagram = diagram
  this.Step = step
  this.ModelloEvento = modelloEvento
   
  this.LoadCustomDataForWkfResultId()
  this.show(Modal)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFFlowDetailForm.openFlowId(
  WkfFlow flow                  // Write a comment for this parameter or press backspace to delete this comment
  DiagramHandler diagramHandler // 
)
{
  Diagram d = diagramHandler.GetDiagram()
   
  if (flow.IDFLOW > 0)
  {
    WkfFlow wf = d.getFlowFromDiagram(flow.IDFLOW)
    this.loadFlowData(wf, diagramHandler)
    this.IsFlowInserted = flow.inserted
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFFlowDetailForm.loadFlowData(
  WkfFlow wkfFlow               // 
  DiagramHandler diagramHandler // 
)
{
  this.DiagramHandler = diagramHandler
  Diagram d = this.DiagramHandler.GetDiagram()
   
  if (wkfFlow and wkfFlow.IDFLOW > 0)
  {
    FlowDetail.setDocument(wkfFlow, false)
     
    WkfStep ws = d.getStepFromDiagram(wkfFlow.IDSTEP)
    IDCollection notAssignedResults of WkfResult = d.getNonAssignedResultsOfStep(ws, wkfFlow)
     
    FlowDetail.IDRESULT.clearValueList()
    for each WkfResult wr in notAssignedResults
    {
      FlowDetail.IDRESULT.addValueListItem(wr.IDRESULT, wr.RESULTDESCRIPTION, ...)
    }
     
    if (notAssignedResults.count() == 1)
    {
      notAssignedResults.moveFirst()
      WkfResult wr = (WkfResult)notAssignedResults.getAt()
       
      if (wr)
      {
         wkfFlow.IDRESULT = wr.IDRESULT
      }
      else 
      {
         UIBusinessLogic.DTTLogMessage("Result broken.", ..., DTTError)
      }
    }
     
    ModelloEvento me = d.ModelloEvento
    if (me.SUPPORTPUBLICINFO == No)
    {
      FlowDetail.Comportamentostatopubblico.setVisible(false)
      FlowDetail.DescriptionEventoPublicStato.setVisible(false)
    }
     
    if (wkfFlow.ISSTART == Yes)
    {
    }
    if (wkfFlow.ISSTOP == Yes)
    {
      FlowDetail.Comportamento.setVisible(true)
      if (FlowDetail.Comportamento == ImpostaSpecifico)
      {
         FlowDetail.Esitieventodropdown.setVisible(true)
      }
       
      FlowDetail.DELAYDAYS.setEnabled(false)
      FlowDetail.ISDATEEDITABLE.setEnabled(false)
    }
    else 
    {
      FlowDetail.Comportamento.setVisible(false)
      FlowDetail.Esitieventodropdown.setVisible(false)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void WKFFlowDetailForm.ButtonSave()
{
  try 
  {
    WkfFlow flow = FlowDetail.document
     
    Diagram d = this.DiagramHandler.GetDiagram()
     
    WkfStep previousStep = d.getStepFromDiagram(flow.IDSTEP)
    WkfStep nextStep = d.getStepFromDiagram(flow.IDNEXTSTEP)
    d.updateFlow(flow)
     
    IDArray errorsArray = new()
    boolean isFlowValid = d.ValidateFlow(previousStep, nextStep, errorsArray, flow, ...)
     
    if (isFlowValid)
    {
      this.close(...)
      this.DiagramHandler.UpdateFlow(flow)
    }
    else 
    {
      // get errors of all properties
       
      string completeErrorMessage = d.GetFlowErrors(flow)
       
      if (completeErrorMessage != "")
      {
         UIBusinessLogic.messageBox(completeErrorMessage)
      }
    }
  }
  catch 
  {
    UIBusinessLogic.messageBox("Non è stato possibile salvare il collegamento.")
  }
}


// ──────────────────────────────────

// ****************************************************************************
// Close the modal form.
// If the user has not selected a result the flow is deleted because is invalid
// ****************************************************************************
public void WKFFlowDetailForm.close()
{
  if (this.IsFlowInserted)
  {
    this.DiagramHandler.removeFlow(FlowDetail.document)
     
  }
   
  this.close(true)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event WKFFlowDetailForm.Load()
{
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event WKFFlowDetailForm.FlowDetail.OnDynamicProperties()
{
  if (FlowDetail.Comportamento == ImpostaSpecifico)
  {
    FlowDetail.Esitieventodropdown.setVisible(true)
  }
  if (FlowDetail.Comportamento == Richiedi)
  {
    FlowDetail.Esitieventodropdown.setVisible(false)
  }
   
  if (FlowDetail.ComportamentoStatoPubblico == ImpostaSpecifico)
  {
    FlowDetail.DescriptionEventoPublicStato.setVisible(true)
  }
  if (FlowDetail.ComportamentoStatoPubblico == Richiedi)
  {
    FlowDetail.DescriptionEventoPublicStato.setVisible(false)
  }
   
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void WKFStepCleanDisposizioniForm.CloseForm()
{
  this.close(...)
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void WKFStepCleanDisposizioniForm.ConfirmDeletion()
{
  this.CleanDisposizioni()
  this.close(...)
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void WKFStepCleanDisposizioniForm.setup(
  WkfStep step // 
)
{
  this.Step = step
   
}


// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void WKFStepCleanDisposizioniForm.CleanDisposizioni()
{
  IDArray errors = new()
   
  IDCollection disps of MultipleStepTemplateDisposizione = this.Step.Disposizioni
   
  for each MultipleStepTemplateDisposizione mstd in disps
  {
    this.Step.RemoveDisposizione(mstd, errors)
  }
   
  if (errors.length() > 0)
  {
    UIBusinessLogic.messageBox("Errore cancellazione disposizioni: <br/>" + Tools.ArrayToString(errors, "<br/>"))
  }
}


// ──────────────────────────────────

// *******************************************************************
// Event raised by the panel when a user changes the data in the panel
// *******************************************************************
event IndicatorDetailForm.IndicatorDetail.OnUpdatingRow(
  int Column // An integer specifying which field triggered the event being executed. The Me property of the panel field should be used to perform comparisons.
  boolean FieldModified    // A boolean value specifying that the field has actually been modified, i.e., its value is different from that originally read from the database.
  boolean FieldWasModified // Since version 6.7.2900, this argument specifies whether the field has changed in the last browser transmission, and can therefore be used to determine which fields have actually...
  boolean RowWasModified   // This argument should not be used; it is present only for compatibility with older versions of Instant Developer.
  boolean Inserting        // A boolean value specifying whether the current row is being edited (false) or inserted (true).
  inout boolean Cancel     // Do not use this argument. To report an error condition, use the SetErrorText functions of the panel field or of the panel itself.
)
{
  if (IndicatorDetail.Scheduled == Yes)
  {
    IDForm schedulerForm = SchedulerForm.newInstance(SubForm, ...)
    IndicatorDetail.LabelScheduler.setVisible(true)
    IndicatorDetail.LabelScheduler.setLabelSubForm(schedulerForm, ...)
  }
  if (IndicatorDetail.Scheduled == No)
  {
    IndicatorDetail.LabelScheduler.setVisible(false)
  }
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event IndicatorDetailForm.IndicatorDetail.OnDynamicProperties()
{
  if (this.Indicator)
  {
    boolean rangeToBeShown = this.Indicator.fieldNeedsToBeEnabled(Range)
    boolean hasRangeEnabled = this.Indicator.fieldNeedsToBeEnabled(HasRange)
    boolean dataProviderTypeEnabled = this.Indicator.fieldNeedsToBeEnabled(DataProviderType)
     
    IndicatorValues.RangeFrom.hiddenInList = !(rangeToBeShown)
    IndicatorValues.RangeTo.hiddenInList = !(rangeToBeShown)
     
    IndicatorDetail.HasRange.setEnabled(hasRangeEnabled)
    IndicatorDetail.DataProviderType.setEnabled(dataProviderTypeEnabled)
     
    if (this.Indicator.HasRange == Yes)
    {
      this.Indicator.beginTransaction()
      this.Indicator.DataProviderType = Manual
      this.Indicator.endTransaction()
    }
  }
}


// ──────────────────────────────────



// ──────────────────────────────────

// ************************************************************
// Spiega quale elaborazione viene eseguita da questa procedura
// ************************************************************
public void IndicatorDetailForm.deleteValue()
{
  IndicatorValue iv = IndicatorValues.document
   
  if (iv)
  {
    iv.deleted = true
  }
   
  IDCollection indicatorValuesCollection of IndicatorValue = IndicatorValues.collection
  if (indicatorValuesCollection.count() == 0)
  {
    Indicator.IndicatorDataProviderSubform.sendMessage("unlockQueryField", null, ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void IndicatorDetailForm.ButtonImpostaResponsabile()
{
  LookupHelper lh = LookupHelper.create(this.IDForm(), Personale, false, null, ...)
  lh.displayLookup()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void IndicatorDetailForm.ButtonRilevaora()
{
  if (this.Indicator)
  {
    if (IndicatorDetail.CodUm == "" or IndicatorDetail.CodUm == null)
    {
      UIBusinessLogic.messageBox("Seleziona l'unità di misura prima di rilevare il valore.")
      IndicatorDetail.CodUm.setEnabled(true)
    }
    else 
    {
      // both types handled on generate instant value
      this.Indicator.generateInstantValue()
       
      Indicator.IndicatorDataProviderSubform.sendMessage("refreshQuery", null, ...)
       
      IndicatorDetail.CodUm.setEnabled(false)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void IndicatorDetailForm.ButtonSalvasuldb()
{
   
  string errorMessage = this.Indicator.saveIndicator(false)
   
  if (errorMessage != "")
  {
    UIBusinessLogic.messageBox(errorMessage)
  }
  else 
  {
    UIBusinessLogic.messageBox("Indicatore salvato con successo.")
    this.ParentListForm.sendMessage("refreshQuery", null, ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void IndicatorDetailForm.ButtonEliminaIndicatore()
{
  if (this.Indicator)
  {
    int response = UIBusinessLogic.messageConfirmEx(formatMessage("Sei sicuro di voler eliminare l'Indicatore |1?", this.Indicator.Description, ...), "SI;NO")
     
    if (response == 1)
    {
      boolean hasIndicatoreBeenDeleted = this.Indicator.deleteIndicatore()
      if (!(hasIndicatoreBeenDeleted))
      {
         UIBusinessLogic.messageBox("Errore nel processo di eliminazione dell'indicatore.")
      }
      else 
      {
         UIBusinessLogic.messageBox("Indicatore eliminato con successo.")
         this.close(...)
         if (this.ParentListForm)
         {
           this.ParentListForm.sendMessage("refreshQuery", null, ...)
         }
      }
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void IndicatorDetailForm.Back()
{
  UIBusinessLogic.DTTLogMessage("BAck button to be centralized", ..., DTTError)
  this.close(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void IndicatorDetailForm.drawDataProviderSubform()
{
  IDForm idf = this.Indicator.IndicatorDataProvider.getSubform()
   
  IndicatorDetail.Labeldataprovider.clearValueList()
  IndicatorDetail.Labeldataprovider.setVisible(true)
  IndicatorDetail.Labeldataprovider.setLabelSubForm(idf, ...)
   
  idf.sendMessage("setDocument", this.Indicator.IndicatorDataProvider, ...)
   
  this.Indicator.IndicatorDataProviderSubform = idf
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static LookupBuilder LookupBuilder.create(
  IDPanel panel // 
)
{
  LookupBuilder vlb = new()
  vlb.setPanel(panel)
  return vlb
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void LookupBuilder.computeValueList(
  int panelFieldIndex                                // 
  IDDocument element                                 // 
  string propertyFieldCodeResult                     // 
  string propertyFieldCodeDescription                // 
  optional string propertyFieldCodeDiscriminant = "" // 
  optional string discriminantFieldValue = ""        // 
)
{
  LookupPerformer vll = LookupPerformer.create(element, propertyFieldCodeResult, propertyFieldCodeDescription, propertyFieldCodeDiscriminant, discriminantFieldValue)
  vll.perform(panelFieldIndex, Panel)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void LookupBuilder.setPanel(
  IDPanel panel // 
)
{
  Panel = panel
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static LookupPerformer LookupPerformer.create(
  IDDocument element                                  // 
  string propertyFieldCodeResult                      // 
  string propertyFieldCodeDescription                 // 
  optional string propertyFieldIndexDiscriminant = "" // 
  optional string discriminantFieldValue = ""         // 
)
{
  LookupPerformer lookup = new()
  lookup.setup(element, propertyFieldCodeResult, propertyFieldCodeDescription, propertyFieldIndexDiscriminant, discriminantFieldValue)
  return lookup
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void LookupPerformer.perform(
  int fieldIndex // 
  IDPanel panel  // 
)
{
  panel.clearFieldValueList(fieldIndex)
  string resultingQuery = this.computeQuery()
  Recordset results = QualibusDB.SQLQuery(resultingQuery)
  if (results.recordCount() > 0)
  {
    results.moveFirst()
    for (int j = 0; j < results.recordCount(); j = j + 1)
    {
      string value = ""
      string description = ""
      for (int i = 1; i <= results.fieldCount(); i = i + 1)
      {
         string fName = results.fieldName(i)
         if (QueryType == singleResult)
         {
           value = if(fName == ResultPropertyDBCode, results.getFieldValue(fName), value)
           description = value
         }
         else 
         {
           value = if(fName == ResultPropertyDBCode, results.getFieldValue(fName), value)
           description = if(fName == DescriptionPropertyDBCode, results.getFieldValue(fName), description)
         }
          
         if (value != "" and description != "")
         {
           panel.addFieldValueListItem(fieldIndex, value, description, description, ...)
         }
      }
      results.moveNext()
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void LookupPerformer.setup(
  IDDocument element                                 // 
  string resultPropertyFieldCode                     // 
  string descriptionPropertyFieldCode                // 
  optional string discriminantPropertyFieldCode = "" // 
  optional string discriminantFieldValue = ""        // 
)
{
   
  DbTableCodeResolver dtcr = DbTableCodeResolver.create(element)
  DBTableName = dtcr.resolveDBTableCode()
   
  DbFieldCodeResolver resultResolver = DbFieldCodeResolver.create(element, resultPropertyFieldCode)
  ResultPropertyDBCode = resultResolver.resolveDBField()
   
  DbFieldCodeResolver descrResolver = DbFieldCodeResolver.create(element, descriptionPropertyFieldCode)
  DescriptionPropertyDBCode = descrResolver.resolveDBField()
   
  if (discriminantFieldValue != "" and discriminantFieldValue != null and discriminantPropertyFieldCode != "" and discriminantPropertyFieldCode != null)
  {
    DbFieldCodeResolver discriminantResolver = DbFieldCodeResolver.create(element, discriminantPropertyFieldCode)
    DiscriminantPropertyDBCode = discriminantResolver.resolveDBField()
    DiscriminantValue = discriminantFieldValue
  }
   
  this.computeQueryType()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void LookupPerformer.computeQueryType()
{
  if (ResultPropertyDBCode != DescriptionPropertyDBCode and (DiscriminantValue == "" or DiscriminantValue == null))
  {
    QueryType = twoResults
  }
  else if (ResultPropertyDBCode != DescriptionPropertyDBCode and (DiscriminantValue != "" or DiscriminantValue != null))
  {
    QueryType = twoResultsWithFilter
  }
  else if (ResultPropertyDBCode == DescriptionPropertyDBCode and (DiscriminantValue == "" or DiscriminantValue == null))
  {
    QueryType = singleResult
  }
  else 
  {
    QueryType = singleResultWithFilter
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private string LookupPerformer.computeQuery()
{
  string sourceQuery = ""
  switch (QueryType)
  {
    case singleResult:
      sourceQuery = "select distinct |1 from |3 order by |1"
    break
    case twoResults:
      sourceQuery = "select distinct |1, |2 from |3 order by |1"
    break
    case singleResultWithFilter:
      sourceQuery = formatMessage("select distinct |1 from |3 where |4 = '|5' order by |1", "|1", "|2", "|3", DiscriminantPropertyDBCode, DiscriminantValue)
    break
    case twoResultsWithFilter:
      sourceQuery = formatMessage("select distinct |1, |2 from |3 where |4 = '|5' order by |1", "|1", "|2", "|3", DiscriminantPropertyDBCode, DiscriminantValue)
    break
  }
   
  string resultingQuery = formatMessage(sourceQuery, ResultPropertyDBCode, DescriptionPropertyDBCode, DBTableName, ...)
  return resultingQuery
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static DbTableCodeResolver DbTableCodeResolver.create(
  IDDocument element // 
)
{
  DbTableCodeResolver resolver = new()
  resolver.setup(element)
  return resolver
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string DbTableCodeResolver.resolveDBTableCode()
{
  return Structure.DBCode
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DbTableCodeResolver.setup(
  IDDocument sourceDoc // 
)
{
  Structure = sourceDoc.getStructure()
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static DbFieldCodeResolver DbFieldCodeResolver.create(
  IDDocument element // 
  string code        // 
)
{
  DbFieldCodeResolver resolver = new()
  resolver.setup(element, code)
  return resolver
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string DbFieldCodeResolver.resolveDBField()
{
  IDPropertyDefinition propertyDefinition = Structure.getPropertyDefinition(PropertyIndex)
  return propertyDefinition.DBCode
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void DbFieldCodeResolver.setup(
  IDDocument sourceDoc // 
  string propertyCode  // 
)
{
  Structure = sourceDoc.getStructure()
  PropertyIndex = sourceDoc.getPropertyIndex(propertyCode, true, true, true, true)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void UIBusinessLogic.initializeGlobalVariables()
{
  UIBusinessLogic.UIBusinessLogicCommunication = UIBusinessLogicCommunication.create()
   
  PanelRowButtonRepository.instantiateSingleton()
  ReferenceTypeMenuController.instantiateSingleton()
   
  QappCoreRuntimeBehavior.instantiateSingleton()
}


// ──────────────────────────────────

// ************************************************************
// Event raised by the document after loading from the database
// ************************************************************
event ModelloEventoWithExtraChecks.AfterLoad(
  boolean AlreadyLoaded     // A boolean parameter that specifies whether the document was previously loaded.
  IDArray LoadedCollections // IDArray type parameter that contains the collections loaded by the framework. If the value of the Already Loaded parameter is False, the Loaded Collections parameter is NULL.
)
{
  this.loadWKFFLOW(...)
  this.loadWKFSTEPS(...)
  base.loadModelloEventoRiferimenti(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean ModelloEventoWithExtraChecks.modelloIsCompatibleWithAnonymousUser(
  inout string errMessage // 
)
{
  // special check that makes sense only for Workflow (while for Normale it is not a problem)
  if (WORKFLOWTYPE == Workflow)
  {
    if (!(this.executoreOfFirstDisposizioneIsManualOrResponsabile()))
    {
      errMessage = "L'esecutore della prima disposizione non è definito nel workflow; il tipo di esecutore dovrebbe essere Manuale o Responsabile"
    }
  }
  if (!(this.modelloResponsibleIsSet()))
  {
    errMessage = "Il responsabile del modello non è definito"
  }
  if (!(this.noMandatoryReferenceOrMandatoryReferenceExistsWithValues()))
  {
    errMessage = "Il modello ha dei tipi riferimento obbligatori e non ci sono riferimenti"
  }
  if (!(this.utenteAnonimoIsAbleToLogin()))
  {
    errMessage = "L'utente anonimo non è in grado di effettuare il login, controllare Attivo e Login"
  }
   
  if (errMessage != "")
  {
    errMessage = errMessage + ", non è possibile utiilzzare un utente anonimo."
  }
  return (errMessage == "")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean ModelloEventoWithExtraChecks.noMandatoryReferenceOrMandatoryReferenceExistsWithValues()
{
  boolean noMandatoryreferenceExists = true
  base.loadModelloEventoRiferimenti(...)
   
  for each ModelloEventoRiferimento mer in ModelloEventoRiferimenti
  {
    if (mer.MANDATORYROWS > 0)
    {
      ReferenceType rt = ReferenceType.get(mer.IDTipoRiferimento)
      IDCollection references of Riferimento = base.GetRiferimenti(rt)
      if (references.count() == 0)
      {
         noMandatoryreferenceExists = false
         break 
      }
    }
  }
   
  return noMandatoryreferenceExists
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean ModelloEventoWithExtraChecks.executoreOfFirstDisposizioneIsManualOrResponsabile()
{
  boolean firstDisposizioniExecutorIsDefined = false
  boolean executorIsManualOrResponsible = false
  boolean executorIsDefined = true
  WkfStep firstStep = base.getFirstStep()
  executorIsManualOrResponsible = ((firstStep.EXECUTORTYPE == Manuale) or (firstStep.EXECUTORTYPE == Responsabile))
  if ((firstStep.EXECUTORTYPE == Manuale) and !((firstStep.IDDIPENDENTE > 0)))
  {
    executorIsDefined = false
  }
   
  firstDisposizioniExecutorIsDefined = executorIsManualOrResponsible and executorIsDefined
  return firstDisposizioniExecutorIsDefined
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public boolean ModelloEventoWithExtraChecks.modelloResponsibleIsSet()
{
  return IDUTENTERESP > 0
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public string ModelloEventoWithExtraChecks.modelloIsCompatibleWithChiusuraAutomatica()
{
  string errMessage = ""
  if (base.hasCustomDataWithMandatoryOnClosureFlag())
  {
    errMessage = "Il modello contiene dei dati personalizzati obbligatori alla chiusura dell'evento"
  }
  if (base.isWorkflowModelloEvento())
  {
    errMessage = "Il modello è di tipo workflow"
  }
  if (base.anyOneDisposizioneExists())
  {
    errMessage = "Il modello ha una o più disposizioni"
  }
   
  if (errMessage != "")
  {
    errMessage = errMessage + ", non è possibile utiilzzare la chiusura automatica."
  }
  return (errMessage)
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static IDCollection ModelloEventoWithExtraChecks.getModelliEventoCompatibleWithAnonymousUser(
  Utente user  // 
  int idClasse // 
)
{
  IDCollection allModelliOfSelectedClass of ModelloEventoWithExtraChecks = new()
  select into collection (allModelliOfSelectedClass)
  from 
    ModelloEventoWithExtraChecks // master table
  where
    ATTIVO == Yes
    WORKFLOWTYPE == Workflow
    IDCLASSE == idClasse
   
  boolean isUserAnonymous = user.isAnonymous()
   
  IDCollection results of ModelloEventoWithExtraChecks = new()
   
  if (!(isUserAnonymous))
  {
    results.addAll(allModelliOfSelectedClass, ...)
  }
  else 
  {
    for each ModelloEventoWithExtraChecks mewec in allModelliOfSelectedClass
    {
      string dummyString = ""
      boolean isModelloCOmpatibleWithAnonymousUser = mewec.modelloIsCompatibleWithAnonymousUser(dummyString)
       
      if (isModelloCOmpatibleWithAnonymousUser)
      {
         results.add(mewec)
      }
    }
  }
   
  return results
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static ModelloEventoWithExtraChecks ModelloEventoWithExtraChecks.get(
  int idModelloEventoWithExtraChecks // 
)
{
  ModelloEventoWithExtraChecks mewec = new()
  mewec.IDTEMPLATEEVENTO = idModelloEventoWithExtraChecks
   
  try 
  {
    mewec.loadFromDB(...)
  }
  catch 
  {
    UIBusinessLogic.DTTLogMessage("Errore nel get del Modello evento with extra checks.", ..., DTTError)
  }
   
  return mewec
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static EventoWizardManager EventoWizardManager.create(
  Utente utente     // 
  UrlToken urlToken // 
)
{
  EventoWizardManager ewm = new()
  ewm.init()
  ewm.Utente = utente
  ewm.URLToken = urlToken
  ewm.populateInputData()
  return ewm
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventoWizardManager.openSecondStepForm()
{
  int matchingIdDipendente = 0
  select into variables (found variable)
    set matchingIdDipendente = IDDIPENDENTE
  from 
    VUTENTIDIPENDENTI // master table
  where
    IDUTENTE == Utente.IDUTENTE
   
  // the last parameter is skipSetting of responsible so in case responsible is not set we do not do the auto setting that QappCore does by default
  Evento = Evento.create(Utente.IDUTENTE, matchingIdDipendente, matchingIdDipendente, IdModello, StartDate, 0, 0, ...)
  UIBusinessLogic.Evento = Evento
  ECFWSecondStep.showForm(Evento)
}


// ──────────────────────────────────



// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void EventoWizardManager.populateInputData()
{
  switch (URLToken.TOKENTYPE)
  {
    case modelloEventoBased:
      IdModello = URLToken.MAINID
      MainModule mm = ModelloEvento.retrieve(ModelliEventi, IdModello, ...)
      ModelloEvento modelloEvento = (ModelloEvento)mm
      if (modelloEvento)
      {
         IdClasse = modelloEvento.IDCLASSE
         ClasseEvento ce = ClasseEvento.get(IdClasse)
         DescriptionClasse = ce.DESCRCLASSE
      }
       
    break
    case classEventoBased:
      IdClasse = URLToken.MAINID
      ClasseEvento ce = ClasseEvento.get(IdClasse)
      DescriptionClasse = ce.DESCRCLASSE
    break
  }
}


// ──────────────────────────────────

// ************************************************************************************************
// centralized method to get the caption for the first and second form of inserimento evento wizard
// 
// note: in fact in first form it is used as form caption and in second as panel caption
// ************************************************************************************************
public string EventoWizardManager.getCommonFormCaption()
{
  string classeDescription = ""
  select into variables (found variable)
    set classeDescription = DESCRCLASSE
  from 
    EVACLASSIEVENTO // master table
  where
    IDCLASSE == IdClasse
   
  string computedCaption = ""
  if (Evento)
  {
    // in second step Evento has been initialzied so we compute a richer caption since we have access to Modello...
    string modelloDescription = Evento.ModelloEvento.DESCRTEMPLATE
    string secondWizardPageParmetrizedTitle = UIBusinessLogic.URLTOKEN.SecondWizardPageTitle
    computedCaption = replace(secondWizardPageParmetrizedTitle, "[CLASSE_EVENTO]", classeDescription)
    computedCaption = replace(computedCaption, "[MODELLO]", modelloDescription)
  }
  else 
  {
    // ... otherwise a minimalistic caption is computed
    string s = UIBusinessLogic.URLTOKEN.FirstWizardPageTitle
     
    computedCaption = replace(s, "[CLASSE_EVENTO]", classeDescription)
  }
   
  return computedCaption
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public static boolean EventoWizardManager.userIsAllowedToCreateAnEvento(
  UrlToken urlToken // 
)
{
  boolean classBased = urlToken.TOKENTYPE == classEventoBased
   
  ClasseEvento classeEvento = null
   
  int idClass = 0
  if (classBased)
  {
    idClass = urlToken.MAINID
    classeEvento = ClasseEvento.get(idClass)
  }
  else 
  {
    ModelloEvento me = ModelloEvento.getFromDB(urlToken.MAINID, ...)
    if (me and me.IDTEMPLATEEVENTO > 0)
    {
      idClass = me.IDCLASSE
      classeEvento = ClasseEvento.get(idClass)
    }
    else 
    {
      X.MessageBox("La procedura guidata non può essere avviata perchè l'url contiene un parametro incorretto.", "Errore", ...)
    }
  }
   
  boolean userHasEnoughPrivilegeToCreateAnEventoOfGivenClass = false
  if (classeEvento and classeEvento.loaded)
  {
    userHasEnoughPrivilegeToCreateAnEventoOfGivenClass = classeEvento.canUserCreateEvento(QappCore.Loggeduser)
    if (!(userHasEnoughPrivilegeToCreateAnEventoOfGivenClass))
    {
      UIBusinessLogic.messageBox(formatMessage("<font color=red>L'utente loggato <b>|1</b> non ha i privilegi necessari per avviare un evento </font>.", QappCore.Loggeduser.DESCRUTENTE, ...))
    }
    else 
    {
      UIBusinessLogic.DTTLogMessage("Inserimento evento effettuato dall'utente " + QappCore.Loggeduser.Username, ...)
    }
  }
   
  return userHasEnoughPrivilegeToCreateAnEventoOfGivenClass
}


// ──────────────────────────────────

// *********************************************
// Raised when the document is being initialized
// *********************************************
event EventoWizardManager.OnInit()
{
  StartDate = today()
}


// ──────────────────────────────────

// ************************************************
// closes all the forms except the one being passed
// ************************************************
public static void UICommonUtils.closeAllFormsButOne(
  IDForm idFormToBeIgnored // 
)
{
  // close all other form (tipically there could be URL token form opened in the same session)
  for (int i = 0; i < UIBusinessLogic.openFormsCount(); i = i + 1)
  {
    IDForm idf = UIBusinessLogic.getOpenForm(i)
    if (idf.GUID() != idFormToBeIgnored.GUID())
    {
      idf.close(...)
    }
  }
}


// ──────────────────────────────────

// *********************************************************************************
// call this in the shofForm of the modal form: the background will become dark blue
// *********************************************************************************
public static void UICommonUtils.makeModalFormWithDarkBackground()
{
  string jsToAssignBlueModalBackgroundClassToModalBackdrop = "$( document).ready(function() { $('.modal-backdrop').addClass('blue-modal-background');});"
  UIBusinessLogic.executeOnClient(jsToAssignBlueModalBackgroundClassToModalBackdrop)
}


// ──────────────────────────────────

// ***************************************
// the 2 parameters are the URL parameters
// ***************************************
public static void OnCommandHandler.doStartEventoWizard(
  string INFO // 
  string AUTH // 
)
{
  UIBusinessLogic.StartEventoWizardAfterLogin = true
  string infoGUID = INFO
   
  UrlToken ut = UrlToken.getByGuid(infoGUID)
  string errorMessage = ""
  if (ut)
  {
    UIBusinessLogic.URLTOKEN = ut
    if (ut.AnonymousLogin)
    {
      Utente anonymousUser = Utente.retrieveAnonymousUser()
      boolean dataValid = false
      QappCore.doLogin(anonymousUser.Username, "", dataValid, errorMessage, true)
       
      if (dataValid)
      {
         QappCore.Loggeduser = anonymousUser
         return 
      }
    }
  }
  else 
  {
    errorMessage = "Invalid token."
  }
   
  if (errorMessage != "")
  {
    QappCore.setLoginMessageForNextSession(errorMessage)
     
  }
   
  // all the below to be reviewd and refactored
  // MOREOVER TOKEN VALIDATION (like expired or not) not considered!!
  // The code that follows is used when wizard is started from Qmobile!
   
   
  string authInfo = AUTH
   
  boolean urlContainsAuthInfo = authInfo != ""
   
  if (urlContainsAuthInfo)
  {
    LoginToken lt = new()
    lt.VALUE = authInfo
    try 
    {
      lt.loadFromDB(...)
      lt.consume()
    }
    catch 
    {
      UIBusinessLogic.DTTLogMessage("Invalid auth info.", ..., DTTError)
    }
     
    Utente u = Utente.get(lt.IDUTENTE)
    QappCore.Loggeduser = u
    UIBusinessLogic.userRole = Administrator
  }
  else 
  {
    // clear any existing visible login error, it makes sense in case errors from previous attemps were displayed, but when we use startEventoWizard we do not want to show errors if link is fine
    UIBusinessLogic.setLoginMessageForStaticMethods("")
     
    // if a session was already started (e.g. a display public info session)
    if (UIBusinessLogic.userRole != null)
    {
      // 
      trick To Store The Start Evento Wizard Url That Generated The Browser Request In A Global Var That Is Used In Restart Session Timer
      {
         // from INFO and urlToken class we are able to reconstruct the url who generated the session
         UrlToken tempUt = new()
         tempUt.setGuid(INFO)
         tempUt.computeURL()
         UIBusinessLogic.RestartSessionUrl = tempUt.Url
      }
       
      // this timer allows to do exit to a CMD, otherwise Inde will not allow it
      // this technique has been suggested in support ticket 000959-2024 (Franesco's ticket)
      RestartSessionTimer.enabled = true
    }
  }
}


// ──────────────────────────────────

// ***************************************
// handles the LDAPTest form for OnCommand
// ***************************************
public static void OnCommandHandler.doTestLDAP(
  string TOKEN // 
)
{
  string expectedFixedToken = "17CFAE75-791D-4FD6-B23C-24BB9C04AF75"
  if (TOKEN != expectedFixedToken)
  {
    UIBusinessLogic.DTTLogMessage(formatMessage("Invalid token (|1) passed, impossible to continue", TOKEN, ...), ...)
    return 
  }
   
  UIBusinessLogic.userRole = Administrator
  LDAPTest.showForm()
   
  for (int i = 0; i < UIBusinessLogic.openFormsCount(); i = i + 1)
  {
    IDForm idf = UIBusinessLogic.getOpenForm(i)
    if (idf.caption == LDAPTest.caption)
    {
      continue 
    }
    else 
    {
      idf.close(true)
    }
  }
}


// ──────────────────────────────────

// *****************************************************
// handles the display Public Info Feature in on command
// *****************************************************
public static void OnCommandHandler.doDisplayPublicInfo(
  string TOKEN // 
  int idEvento // 
)
{
   
  if (TOKEN != "" and idEvento > 0)
  {
    string expectedFixedToken = "17CFAE75-791D-4FD6-B23C-24BB9C04AF75"
    Evento e = Evento.getFromDB(idEvento, ...)
    if (TOKEN != expectedFixedToken)
    {
      UIBusinessLogic.DTTLogMessage(formatMessage("Invalid token (|1) passed, impossible to continue", TOKEN, ...), ...)
      return 
    }
    UIBusinessLogic.userRole = Administrator
    ConfirmationForm.showForm(e, displayPublicInfoDetails)
  }
  else 
  {
    UIBusinessLogic.messageBox("Errore, token oppure id evento non corretti.")
  }
}


// ──────────────────────────────────

// ****************************************************
// handles the search Public Info Feature in on command
// ****************************************************
public static void OnCommandHandler.doSearchPublicInfo(
  string guid               // 
  optional int sourceId = 0 // 
)
{
  UIBusinessLogic.userRole = Administrator
  EventoPublicInfo.showForm(guid, sourceId)
}


// ──────────────────────────────────

// ****************************************************************************************
// handles the search Public Info Feature in on command, it returns a string for On Command
// ****************************************************************************************
public static void OnCommandHandler.doDisplayVersion()
{
  string qappCoreVersion = VersionInfo.getQualibusVersion()
  UIBusinessLogic.setLoginMessageForStaticMethods(formatMessage("Versione: |1", qappCoreVersion, ...))
}


// ──────────────────────────────────

// ****************************************************************************************
// handles the search Public Info Feature in on command, it returns a string for On Command
// ****************************************************************************************
public static void OnCommandHandler.doFirstRun(
  boolean silent // 
)
{
  TabParametri.createQualibusWebBaseUrlFieldIfNeeded()
  TabParametri.createIdUtenteAnonymousFieldIfNeeded()
  UIBusinessLogic.storeQualibusWebUrlInDatabaseIfNeeded(silent)
}


// ──────────────────────────────────

// ***************************************************
// performs the copy url button clicked for On Command
// ***************************************************
public static void OnCommandHandler.doCopyUrlButtonClicked(
  int idModello // 
  int idClasse  // 
)
{
  UIBusinessLogic.userRole = Administrator
  TokenUrlConfiguration tuc = TokenUrlConfiguration.newInstance(...)
  tuc.ShowForm(idModello, idClasse, true)
}


// ──────────────────────────────────

// ****************************************************************************************************************************************************************************************************************
// This readme method explains the workflow/know how of Evento creation wizard. 
// 
// explanation of how this part works (in sequence) 
// 
// it contains four important things which are needed to start wzard susscessfully  
// 1.URL Token class : It hold the records from QBW_URL_TOKENS. It contains a GUID,InfoContent(json data of user selected on "copy url from",MainID(ID_CLASSE/ID_MODELLO) and Type=ClassBased/ModelloBased  
// 
// 2.Copy URL Form : This form is based on URL token class and at this moment it is opened from qualibus c/s Modello Evento and TabelleEventi->Classe. 
// This allows you generate and modify existing link, also it saves the changes on the form immediately. 
// Here on this form you can select whether you want to show mandatory or all custom data
// 
// 3.Evento Wizard Manager class: This class holds the input data and related logic to start evento creation wizard.
// 
// 4.Evento Insertion First Step Form: This form is based on "Evento Wizard Manager" class, this is opened from After login Event.
// This form display Date.Class and modello based on url token passed as input.
// 
// 5.Second Step Evento Insertion Form: This form is called from "Evento Insertion First Step Form" when user has filled all required information, an evnto is created and passed to this form. This form also
// create 3 subforms (later we can create more if required)
//   I. Disposizioni: This panel is part of tabbed view at design time.
//  II. Custom data : This is subform created run time.  
// III. Reference Tad : This is subform created run time.  
// 
// 6.Cdata Helper : It is class to that old "VALUE1...VALUE100" fields to create maximum 100 customdata and IDMAP (cdata Mapping) to hold the tags for all generated customdata including its value.
// 
// 7.Custom data form  : This form is created as subform in the "Evento Insertion First Step Form" and loaded using communication with SEND_MESSAGES from and to "Evento Insertion First Step Form". All the methods
// related to rendering of the customdata fields belongs to this form.
// 
// 8.Reference Tab: This form is a empty form having only a tabbed view where we attach multiple subforms of reference types, so each reference type will have different subform.
// 
// 9.Riferimenti: This form is based on Riferimenti class and it is attached under tabbed view of "Reference Tab" as subform,
// 
// ****************************************************************************************************************************************************************************************************************
public void UIBusinessLogic.README()
{
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event LDAPTest.Load()
{
   
  // to avoid a very rare case in which UrlToken form is already opened we make sure LDAPTest form goes on top
  this.bringToFront()
  X.executeOnClient("hideMainHeader();")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void LDAPTest.FocusTimer()
{
  LDAPTestpanel.username.setFocus(...)
  FocusTimer.enabled = false
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void LDAPTest.showForm()
{
  UICommonUtils.closeAllFormsButOne(this.IDForm())
   
  TabParametri tp = TabParametri.getInstance()
   
  // setting the value of all 4 fields every time ensures that also in case a session was started before it will work
  LDAPTestpanel.IndirizzoIPserverLDAPNewPanel = tp.LDAPIPADDRESS
  LDAPTestpanel.PortaServerLDAP = tp.LDAPPORT
  NewPanel.username = ""
  NewPanel.password = ""
  FocusTimer.enabled = true
   
  LDAPTestpanel.username.setFocus(...)
   
  UIBusinessLogic.widgetMode = true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void LDAPTest.ButtonTEST()
{
  TabParametri tp = TabParametri.getInstance()
  string s = tp.getLdapCompleteAddress()
   
  string username = NewPanel.username
  string password = NewPanel.password
   
  if (username == "" or password == "")
  {
    return 
  }
   
  boolean validLdapCredentials = canConnectToLdapServer(s, username, password)
  string message = ""
  if (validLdapCredentials)
  {
    message = "Autenticazione riuscita"
  }
  else 
  {
    string errorMessage = getLdapConnectionMeessage(s, username, password)
    message = formatMessage("Autenticazione non riucita per server '|1' e username '|2', dettagli errore: |3", s, username, errorMessage, ...)
  }
  UIBusinessLogic.messageBox(message)
}


// ──────────────────────────────────

// **********************************************************************
// Called every 1 second. Closes the application and redirects the user
// to the login page if inactive for more than 60 (parametrized thanks to
// the getInactivityTimeoutInSeconds() method) seconds.
// **********************************************************************
public void EventoPublicInfo.InactivityClosureTimer()
{
  InactivityClosureTimer.enabled = false
   
  int inactivityTimeoutInSeconds = getInactivityTimeoutInSeconds()
   
  boolean isSTillActive = DTH.isYoungerThan(this.LastActivityDatetime, Second, inactivityTimeoutInSeconds)
   
  this.updateDisconnectionInfoLabels()
   
  if (!(isSTillActive))
    Tools.performExit(...)
  InactivityClosureTimer.enabled = true
}


// ──────────────────────────────────

// ***************************************************************
// Updates LastActivityDatetime to now(). Call this on every user
// interaction to keep the inactivity timer from closing the form.
// ***************************************************************
public void EventoPublicInfo.recordUserActivity()
{
  this.LastActivityDatetime = now()
}


// ──────────────────────────────────

// *******************************************************************
// Event raised by the panel when a user changes the data in the panel
// *******************************************************************
event EventoPublicInfo.SearchbyGuid.OnUpdatingRow(
  int Column // An integer specifying which field triggered the event being executed. The Me property of the panel field should be used to perform comparisons.
  boolean FieldModified    // A boolean value specifying that the field has actually been modified, i.e., its value is different from that originally read from the database.
  boolean FieldWasModified // Since version 6.7.2900, this argument specifies whether the field has changed in the last browser transmission, and can therefore be used to determine which fields have actually...
  boolean RowWasModified   // This argument should not be used; it is present only for compatibility with older versions of Instant Developer.
  boolean Inserting        // A boolean value specifying whether the current row is being edited (false) or inserted (true).
  inout boolean Cancel     // Do not use this argument. To report an error condition, use the SetErrorText functions of the panel field or of the panel itself.
)
{
  if (Column == SearchbyGuid.Code.me())
  {
    this.recordUserActivity()
  }
}


// ──────────────────────────────────

// ***************************************************************************************************
// computes the text to be shown in the info labels and assign it to the labels text (one per tabpage)
// ***************************************************************************************************
private void EventoPublicInfo.updateDisconnectionInfoLabels()
{
  int inactivityTimeoutInSeconds = getInactivityTimeoutInSeconds()
  int elapsedSecondsAfterLastActivity = (now() - this.LastActivityDatetime) * 3600 * 24
  int secondsBeforeDisconnection = inactivityTimeoutInSeconds - elapsedSecondsAfterLastActivity
   
  // avoid that -1 is displayed
  if (secondsBeforeDisconnection < 0)
    secondsBeforeDisconnection = 0
   
  string disconnectionInfo = formatMessage("(disconnessione per inattività tra: |1s)", secondsBeforeDisconnection, ...)
   
  SearchbyGuid.LabelDISCINFOFIRSTTAB.text = disconnectionInfo
  EventoPublicInfo.LabelDISCINFOSECONDTAB.text = disconnectionInfo
}


// ──────────────────────────────────

// *****************************************
// centralized inactivity timeout in seconds
// *****************************************
private int EventoPublicInfo.getInactivityTimeoutInSeconds()
{
  return 60
}


// ──────────────────────────────────

// ********************************************************************
// Opens the form in widget mode. Initializes the inactivity timer and,
// if a GUID is provided, loads the related event directly; otherwise
// shows the search panel.
// ********************************************************************
public void EventoPublicInfo.showForm(
  optional string GUID = ""  // 
  optional int idModello = 0 // 
)
{
  this.recordUserActivity()
  this.updateDisconnectionInfoLabels()
  InactivityClosureTimer.enabled = true
   
  this.GUID = GUID
   
  if (GUID == "")
  {
    MainTabbedView.selectPage(SearchbyGuid.me())
  }
  else 
  {
    this.searchByGuid(GUID)
  }
   
  UIBusinessLogic.widgetMode = true
  this.computeTitle(idModello)
}


// ──────────────────────────────────

// **************************************************************
// Records user activity, then triggers the search using the GUID
// entered in the search panel.
// **************************************************************
public void EventoPublicInfo.Buttonsearchbyguid()
{
  this.recordUserActivity()
  this.searchByGuid(SearchbyGuid.Code)
}


// ──────────────────────────────────

// ********************************************************************
// Looks up an event by GUID. If found, populates the form and switches
// to the info page. If not found, shows an error message.
// ********************************************************************
public void EventoPublicInfo.searchByGuid(
  string guid // 
)
{
  EventoPublicInfo epi = EventoPublicInfo.getByGuid(guid)
  if (epi)
  {
    MainTabbedView.selectPage(EventoPublicInfo.me())
    EventoPublicInfo.setDocument(epi, true)
     
    EventoPublicInfo.LabelInformazioni.caption = epi.getSuccessCaptionForPublicInfoForm()
     
    // notes are always visible as required
    boolean notesExist = epi.Notes != ""
//    EventoPublicInfo.Notes.setVisible(notesExist)
    EventoPublicInfo.showInfoMessages = true
     
    this.showMessage(INFO, "Informazioni trovate!", ...)
  }
  else 
  {
  }
}


// ──────────────────────────────────

// *************************************************************
// Records user activity, clears the search field, and navigates
// back to the search panel
// *************************************************************
public void EventoPublicInfo.Buttonbacktosearch()
{
  this.recordUserActivity()
   
  SearchbyGuid.Code = ""
  MainTabbedView.selectPage(SearchbyGuid.me())
}


// ──────────────────────────────────

// ********************************************************************
// Determines the form title: uses a model-specific title from UrlToken
// if idModello is provided, otherwise falls back to the default title
// ********************************************************************
private void EventoPublicInfo.computeTitle(
  int idModello // 
)
{
  string computedTitle = "Consultazione stato pubblico eventi"
   
  if (idModello > 0)
  {
    UrlToken ut = new()
    ut.TOKENTYPE = modelloEventoBased
    ut.MAINID = idModello
    try 
    {
      ut.loadFromDB(...)
      computedTitle = ut.ConsultazionePublicInfoTitle
    }
    catch 
    {
      computedTitle = "Consultazione stato pubblico eventi"
    }
  }
   
  this.caption = computedTitle
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event EventoPublicInfo.Load()
{
  X.executeOnClient("hideMainHeader();")
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event TokenUrlConfiguration.Load()
{
  boolean debugEnabled = X.debugIsOn()
   
  // humanReadableInfo is meant to be shown only when compiled with debug
  TokenUrl.HumanReadableInfo.setVisible(debugEnabled)
}


// ──────────────────────────────────

// **********************************************************************
// Allows the visual properties of individual panel cells to be adjusted.
// **********************************************************************
event TokenUrlConfiguration.TokenUrl.OnDynamicProperties()
{
  if (this.DatabaseConncetionStatus == null)
  {
    // OnDynamicProperties fires many time: the first time enter here and check for errors...
    this.handleDatabaseConnectionIssues()
    return 
  }
  else if (this.DatabaseConncetionStatus != connectionSuccesful)
  {
    // ...and from second time on, return immediately in case of errors
    return 
  }
   
  UrlToken ut = TokenUrl.document
  if (ut)
  {
    string:tokenTypes tokenType = ut.TOKENTYPE
    TokenUrl.ConsultazionePublicInfoTitle.setVisible(tokenType == modelloEventoBased)
     
    TokenUrl.FirstWizardPageTitle.setVisible(ut.AllowChangeDate)
     
    // by default we show public info fields(such in case of idclasse url token)...
    boolean showPublicInfoFields = true
    if (this.IdModello > 0)
    {
      // ... in case of modello evento we can set it to No in case modello does not support PubInfo
      showPublicInfoFields = this.ModelloEvento.SUPPORTPUBLICINFO == Yes
    }
     
    TokenUrl.pubicinfogroup.setGroupVisible(showPublicInfoFields)
     
    if (ut.AnonymousLogin == true)
    {
      ut.NascondiDisposizioni = true
    }
  }
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TokenUrlConfiguration.ShowForm(
  int idModello                // 
  int idClasse                 // 
  boolean openedFromQualibusCS // 
)
{
  this.intializeProperties(idModello, idClasse)
  NewPanel.url = ""
   
  this.IdModello = idModello
  this.IdClasse = idClasse
   
   
  this.handleActionsBasedTokenType()
   
   
  if (this.MainId > 0 and this.TokenType != "")
  {
    this.prepareTokenUrl(this.MainId, this.TokenType)
  }
  else 
  {
    UIBusinessLogic.DTTLogMessage("Unsupported case", ..., DTTError)
  }
   
  string currentCssClass = this.CSSClass
  if (openedFromQualibusCS)
  {
    UICommonUtils.closeAllFormsButOne(this.IDForm())
     
    currentCssClass = currentCssClass + " inserimento-evento"
    this.CSSClass = currentCssClass
    this.bringToFront()
     
    UIBusinessLogic.widgetMode = true
  }
  else 
  {
    currentCssClass = replace(currentCssClass, "inserimento-evento", "")
  }
   
  this.show(...)
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void TokenUrlConfiguration.prepareTokenUrl(
  int mainId                  // 
  string:tokenTypes tokenType // 
)
{
  UrlToken ut = UrlToken.create(mainId, tokenType)
  TokenUrl.setDocument(ut, true)
  boolean chiusuraAutomaticaVisible = TokenUrl.ChiusuraAutomatica.getVisible()
  if (!(chiusuraAutomaticaVisible))
  {
    ut.ChiusuraAutomatica = false
    ut.EventoClosureEsito = ""
  }
   
  if (this.ModelloEvento)
  {
    if (this.ModelloEvento.IDAMBITO <= 0)
    {
      ut.HideAmbito = false
    }
    if (this.ModelloEvento.IDTIPOLOGIA <= 0)
    {
      ut.HideTipologia = false
    }
  }
   
  // set esiti map in UT object, this map will utilized at class side to get the ID Esito from the string value 
  ut.setEsitiMap(this.EsitiMap)
  ut.setTag("anonymousError", this.AnonymousUserErrorMessage)
  if (this.AnonymousUserErrorMessage != "")
    ut.AnonymousLogin = false
   
  ut.setTag("chiusuraAutomaticaError", this.ChiusuraAutomaticaErrorMessage)
  if (this.ChiusuraAutomaticaErrorMessage != "")
  {
    ut.ChiusuraAutomatica = false
    ut.EventoClosureEsito = ""
  }
  ut.ComputeAll()
  try 
  {
    ut.saveToDB(...)
  }
  catch 
  {
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void TokenUrlConfiguration.intializeProperties(
  int idModello // 
  int idClasse  // 
)
{
  this.IdModello = idModello
  this.IdClasse = idClasse
  if (idModello != 0 and idClasse == 0)
  {
    this.TokenType = modelloEventoBased
    this.MainId = idModello
  }
  else if (idModello == 0 and idClasse != 0)
  {
    this.TokenType = classEventoBased
    this.MainId = idClasse
  }
   
  if (this.IdModello > 0)
  {
    this.ModelloEvento = ModelloEvento.getFromDB(idModello, ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TokenUrlConfiguration.handleActionsBasedTokenType()
{
  if (this.TokenType == modelloEventoBased)
  {
    this.ModelloEventoWithExtraChecks = new()
    this.ModelloEventoWithExtraChecks.IDTEMPLATEEVENTO = this.IdModello
    try 
    {
      this.ModelloEventoWithExtraChecks.loadFromDB(...)
    }
    catch 
    {
      this.ModelloEventoWithExtraChecks = null
      return 
    }
    this.AnonymousUserErrorMessage = ""
    this.ChiusuraAutomaticaErrorMessage = ""
    this.ModelloEventoWithExtraChecks.modelloIsCompatibleWithAnonymousUser(this.AnonymousUserErrorMessage)
    this.hideFieldsInCaseOfModelloEvento(this.ModelloEventoWithExtraChecks)
    this.ChiusuraAutomaticaErrorMessage = this.ModelloEventoWithExtraChecks.modelloIsCompatibleWithChiusuraAutomatica()
  }
  else if (this.TokenType == classEventoBased)
  {
    this.hideFieldsInCaseOfClasseEvento()
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TokenUrlConfiguration.populateEventoClosureEsiti()
{
  TokenUrl.EventoClosureEsito.clearValueList()
  this.EsitiMap = this.ModelloEvento.getAvailableEsiti()
  IDArray ida = this.EsitiMap.getKeys()
  for (int j = 0; j < ida.length(); j = j + 1)
  {
    string key = ida.getValue(j)
    string keyValue = this.EsitiMap.getValue(key)
    TokenUrl.EventoClosureEsito.addValueListItem(key, keyValue, keyValue, ...)
     
  }
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void TokenUrlConfiguration.ButtonCopyUrl()
{
  UrlToken ut = TokenUrl.document
  if (ut)
  {
    AppTools.copyStringToClipboard(ut.Url)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void TokenUrlConfiguration.Buttoncopypublicinfourl()
{
  EventoPublicInfo epi = new()
  string s = epi.getCodelessPublicInfoUrl()
   
  UrlToken ut = TokenUrl.document
   
  if (ut.TOKENTYPE == modelloEventoBased)
  {
    s = replace(s, "&MODELLO_ID=0", formatMessage("&MODELLO_ID=|1", this.IdModello, ...))
  }
  else 
  {
    s = replace(s, "&MODELLO_ID=0", "")
  }
   
  string publicAccessLink = s
  AppTools.copyStringToClipboard(publicAccessLink)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void TokenUrlConfiguration.hideFieldsInCaseOfClasseEvento()
{
  TokenUrl.AllowChangeDate.setVisible(false)
  TokenUrl.HideTitle.setVisible(false)
  TokenUrl.HideTipologia.setVisible(false)
  TokenUrl.HideAmbito.setVisible(false)
  TokenUrl.AnonymousLogin.setVisible(false)
   
}


// ──────────────────────────────────

// ************************************************************************************************************************************
// this procedure sets default fields visibilities
// if the modello Evento corrisponding to Idmodello (argument) has tipologia/Ambito/Title then show/hide the panel corrisponding fields
// ************************************************************************************************************************************
private void TokenUrlConfiguration.hideFieldsInCaseOfModelloEvento(
  ModelloEvento modello // 
)
{
  // default visibilities
  TokenUrl.AllowChangeDate.setVisible(true)
  TokenUrl.HideTitle.setVisible(true)
  TokenUrl.HideTipologia.setVisible(true)
  TokenUrl.HideAmbito.setVisible(true)
   
  // if the modello hasn't Tipologia/Ambito/Title hide Tipologia/Ambito/Title Field
  if (modello)
  {
    boolean modelloHasTipologia = modello.IDTIPOLOGIA > 0
    boolean modelloHasAmbito = modello.IDAMBITO > 0
    boolean modelloHasTitolo = modello.DESCRTITOLO != ""
    boolean modelloSupportsPublicStatus = modello.SUPPORTPUBLICINFO == Yes
     
    TokenUrl.HideTipologia.setVisible(modelloHasTipologia)
    TokenUrl.HideAmbito.setVisible(modelloHasAmbito)
    TokenUrl.HideTitle.setVisible(modelloHasTitolo)
     
    // publicStatus related fields
    TokenUrl.GUIDInfoDescription.setVisible(modelloSupportsPublicStatus)
    TokenUrl.Buttoncopypublicinfourl.setVisible(modelloSupportsPublicStatus)
     
    // populate esiti selection in field
    this.populateEventoClosureEsiti()
     
  }
}


// ──────────────────────────────────

// ******************************************************************************************************************
// in case the app is not able to connect to database we inform the user with a nicer error compared to the red error
// this method is called in several places
// ******************************************************************************************************************
private void TokenUrlConfiguration.handleDatabaseConnectionIssues()
{
   
  // if databaseConnectionFailure is already copmuted do not run the query
  if (this.DatabaseConncetionStatus == null)
  {
    try 
    {
      int vCount = 0
      select into variables (found variable)
         set vCount = count(...)
      from 
         Utenti // master table
       
      if (this.IdModello > 0)
      {
         ModelloEvento me = ModelloEvento.getFromDB(this.IdModello, quickLoad)
         if (me == null)
         {
           this.DatabaseConncetionStatus = likelyConnectedToAWrongDatabase
         }
         else 
         {
           this.DatabaseConncetionStatus = connectionSuccesful
         }
      }
      if (this.IdClasse > 0)
      {
         ClasseEvento ce = ClasseEvento.get(this.IdClasse)
         if (ce == null)
         {
           this.DatabaseConncetionStatus = likelyConnectedToAWrongDatabase
         }
         else 
         {
           this.DatabaseConncetionStatus = connectionSuccesful
         }
      }
    }
    catch 
    {
      this.DatabaseConncetionStatus = impossibleToConnectToDatabase
    }
  }
   
   
  if (this.DatabaseConncetionStatus != connectionSuccesful)
  {
    this.caption = formatMessage("|1 (errore di connessione al database: |2)", this.caption, decode(this.DatabaseConncetionStatus, QualibusDatabaseConnectionStatuses), ...)
    TokenUrl.Buttoncopyurl.setEnabled(false)
    TokenUrl.locked = true
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event ECFWFirstStep.Load()
{
  this.bringToFront()
  EventoWizardDatePage.collapsable = false
  X.executeOnClient("hideMainHeader();")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ECFWFirstStep.showForm(
  Utente utente     // 
  UrlToken urlToken // 
)
{
  this.UrlToken = urlToken
  UIBusinessLogic.widgetMode = true
  UIBusinessLogic.EventoWizardManager = EventoWizardManager.create(utente, urlToken)
   
  // check for privilege if user is allowed to create an evento
  if (userIsAllowedToCreateAnEvento(urlToken))
  {
    boolean isClassBased = urlToken.TOKENTYPE == classEventoBased
    EventoWizardDatePage.IDModello.setVisible(isClassBased)
    this.setConfermaButtonCaption(isClassBased)
    if (isClassBased)
    {
      this.checkAtLeastOneModello(utente, urlToken)
    }
     
    // set the caption
    this.caption = UIBusinessLogic.EventoWizardManager.getCommonFormCaption()
     
    // set the document
    EventoWizardDatePage.setDocument(UIBusinessLogic.EventoWizardManager, true)
     
    if (urlToken.AllowChangeDate == false and urlToken.TOKENTYPE == modelloEventoBased)
    {
      this.proceedToNextForm()
    }
  }
   
  if (this.UrlToken.DisplayLogo)
  {
    string logoFileName = TabParametri.extractPrintLogoToImageFolder("logo")
     
    EventoWizardDatePage.imagePlaceholder.loadImage(logoFileName)
  }
  else 
  {
    EventoWizardDatePage.imagePlaceholder.setVisible(false)
  }
   
}


// ──────────────────────────────────

// ***********************************************************************************************
// this procedure checks if EventoWizardManager's IDModello attribute has value. 
// In case it hasn't the IDModello we notify the user that it has to select one modello to proceed
// Otherwise we open the second step of this wizard
// ***********************************************************************************************
private void ECFWFirstStep.proceedToNextForm()
{
  if ((toString(UIBusinessLogic.EventoWizardManager.IdModello) == "") or (isNull(UIBusinessLogic.EventoWizardManager.IdModello)))
  {
    UIBusinessLogic.messageBox("Selezionare il modello di evento per creare un evento.")
  }
  else 
  {
    UIBusinessLogic.EventoWizardManager.openSecondStepForm()
    this.close(...)
  }
}


// ──────────────────────────────────

// ***********************************************************************************************
// the modello evento drop down is populted, in case at least one item is added the result is true
// ***********************************************************************************************
private boolean ECFWFirstStep.prepareModelloDropDown(
  Utente utente // 
  int idClasse  // 
)
{
//  IDCollection allModelliOfThisClass of ModelloEventoWithExtraChecks = new()
//  //  
//  // retrieve all modelli
//  select into collection (allModelliOfThisClass)
//  from 
//    ModelloEventoWithExtraChecks // master table
//  where
//    ATTIVO == Yes
//    WORKFLOWTYPE == Workflow
//    IDCLASSE == idClasse
//   
//  // in case of anonymous remove the not ok ones
//  int dropDownItemsCount = 0
//  boolean userIsAnonymous = utente.isAnonymous()
//  EventoWizardDatePage.IDModello.clearValueList()
//  for each ModelloEventoWithExtraChecks mewec in allModelliOfThisClass
//  {
//    boolean itemToBeAdded = false
//     
//    string dummyMessage = ""
//     
//    if (!(userIsAnonymous))
//    {
//      itemToBeAdded = true
//    }
//    else 
//    {
//      boolean modelloCompatibleWithAnonymousb = mewec.modelloIsCompatibleWithAnonymousUser(dummyMessage)
//      if (modelloCompatibleWithAnonymousb)
//      {
//         itemToBeAdded = true
//      }
//    }
//    if (itemToBeAdded)
//    {
//      dropDownItemsCount = dropDownItemsCount + 1
//      EventoWizardDatePage.IDModello.addValueListItem(mewec.IDTEMPLATEEVENTO, mewec.DESCRTEMPLATE, mewec.DESCRTEMPLATE, ...)
//    }
//  }
//   
  EventoWizardDatePage.IDModello.clearValueList()
  IDCollection modelliEventoCompatibleWithAnonymousUser of ModelloEventoWithExtraChecks = ModelloEventoWithExtraChecks.getModelliEventoCompatibleWithAnonymousUser(utente, idClasse)
   
  for each ModelloEventoWithExtraChecks mewec in modelliEventoCompatibleWithAnonymousUser
  {
    EventoWizardDatePage.IDModello.addValueListItem(mewec.IDTEMPLATEEVENTO, mewec.DESCRTEMPLATE, mewec.DESCRTEMPLATE, ...)
  }
   
  return modelliEventoCompatibleWithAnonymousUser.count() > 0
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private boolean ECFWFirstStep.userIsAllowedToCreateAnEvento(
  UrlToken urlToken // 
)
{
//  boolean classBased = urlToken.TOKENTYPE == classEventoBased
//   
//  ClasseEvento classeEvento = null
//   
//  // check for privilege if user is allowed to create an evento
//   
//  int idClass = 0
//  if (classBased)
//  {
//    idClass = urlToken.MAINID
//    classeEvento = ClasseEvento.get(idClass)
//  }
//  else 
//  {
//    ModelloEvento me = ModelloEvento.getFromDB(urlToken.MAINID, ...)
//    if (me and me.IDTEMPLATEEVENTO > 0)
//    {
//      idClass = me.IDCLASSE
//      classeEvento = ClasseEvento.get(idClass)
//       
//    }
//    else 
//    {
//      X.MessageBox("La procedura guidata non può essere avviata perchè l'url contiene un parametro incorretto.", "Errore", ...)
//    }
//  }
//   
//  boolean userHasEnoughPrivilegeToCreateAnEventoOfGivenClass = classeEvento.canUserCreateEvento(QappCore.Loggeduser)
//  if (classeEvento and classeEvento.loaded)
//  {
//    userHasEnoughPrivilegeToCreateAnEventoOfGivenClass = classeEvento.canUserCreateEvento(QappCore.Loggeduser)
//    if (!(userHasEnoughPrivilegeToCreateAnEventoOfGivenClass))
//    {
//      UIBusinessLogic.messageBox(formatMessage(" <font color=red>L'utente loggato <b>|1</b> non ha i privilegi necessari per avviare un evento </font>.", QappCore.Loggeduser.DESCRUTENTE, ...))
//       
//      // start end timer
//      userHasEnoughPrivilegeToCreateAnEventoOfGivenClass = false
//    }
//    else 
//    {
//      UIBusinessLogic.DTTLogMessage("Inserimento evento effettuato dall'utente " + QappCore.Loggeduser.Username, ...)
//    }
//  }
   
  boolean canUserCreateAnEvento = EventoWizardManager.userIsAllowedToCreateAnEvento(urlToken)
   
  if (!(canUserCreateAnEvento))
  {
    EventoWizardDatePage.StartDate.setVisible(false)
    EventoWizardDatePage.ButtonConfirm.setVisible(false)
    EventoWizardDatePage.IDModello.setVisible(false)
     
    CloseSession.enabled = true
  }
  return canUserCreateAnEvento
}


// ──────────────────────────────────

// ******************************************************************
// if it is class based the user could choose also the Modello Evento
// Otherwise it can choose only the date, so we show "Conferma Data"
// ******************************************************************
private void ECFWFirstStep.setConfermaButtonCaption(
  boolean isClassBased // 
)
{
  EventoWizardDatePage.ButtonConfirm.text = if(isClassBased, "Conferma", "Conferma Data")
}


// ──────────────────────────────────

// ****************************************************
// this procedure checks if there is at least 1 modello
// In case there's not it shows an error
// ****************************************************
private void ECFWFirstStep.checkAtLeastOneModello(
  Utente utente     // 
  UrlToken urlToken // 
)
{
  boolean atLeastOneModelloAdded = this.prepareModelloDropDown(utente, urlToken.MAINID)
  if (!(atLeastOneModelloAdded))
  {
    EventoWizardDatePage.ButtonConfirm.setVisible(false)
    EventoWizardDatePage.IDModello.setVisible(false)
    this.showMessage(ERROR, "Nessun modello disponibile, contattare un amministratore", ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ECFWFirstStep.logutbutton()
{
  Tools.performExit(...)
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event ECFWSecondStep.Load()
{
  Eventoinsertionpanel.collapsable = false
//  Eventoinsertionpanel.setErrorMode(None, None, None, None)
  QappCore.InhibitCdataRenderingHelperQuickValidation = true
  X.executeOnClient("hideMainHeader();")
}


// ──────────────────────────────────

// *********************************************************************
// The Tabbed View object raises this event when the active page changes
// *********************************************************************
event ECFWSecondStep.TabbedView.ChangePage(
  int PreviousPage     // An integer representing the index of the page previously selected in the Tabbed View. Use the Me function of the panel or visual object contained in the Tabbed View to make the comp...
  inout boolean Cancel // If set to True, cancels the page change.
)
{
  // IMPORTANT: this code is never fired since we disable tabbed view with CSS, anyway just in case we keep it to protect against attempts to change tabs
   
  // after insertion of evento we do not allow to change tab
  if (this.FormLocked)
  {
    Cancel = true
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ECFWSecondStep.ClosePageTimer()
{
  string redirectTo = if(UIBusinessLogic.RedirectUrl != "", UIBusinessLogic.RedirectUrl, "???")
  ClosePageTimer.enabled = false
  Tools.performExit(redirectTo)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ECFWSecondStep.showForm(
  Evento evento // Write a comment for this parameter or press backspace to delete this comment
)
{
  if (evento)
  {
    Eventoinsertionpanel.caption = UIBusinessLogic.EventoWizardManager.getCommonFormCaption()
    Eventoinsertionpanel.setDocument(evento, true)
    this.makeAmbitoDropdownReadonlyIfNeeded()
    this.makeTipologiaDropdownReadonlyIfneeded()
    this.handleResponsabileDropDown()
    this.setupTabs(evento)
    this.assignVisibilitiesToMainFieldsBasingOnURLToken()
     
    string commonCreaEventoButtonCaption = UIBusinessLogic.URLTOKEN.getCompleteCreaEventoCaption()
    Eventoinsertionpanel.ButtonCreaEventoTop.text = commonCreaEventoButtonCaption
    Eventoinsertionpanel.ButtonCreaEventoBottom.text = commonCreaEventoButtonCaption
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ECFWSecondStep.lockForm()
{
  this.FormLocked = true
  Eventoinsertionpanel.locked = true
  Eventoinsertionpanel.ButtonCreaEventoTop.setEnabled(false)
  Eventoinsertionpanel.ButtonCreaEventoBottom.setEnabled(false)
  this.hasCloseButton = false
   
  for (int i = 0; i < this.SubformsArray.length(); i = i + 1)
  {
    IDForm idf = (IDForm)this.SubformsArray.getObject(i)
    idf.sendMessage("LOCK_PANELS", ...)
  }
   
  // we add a space in case a class is defined...
  string existingClass = if(TabbedView.CSSClass != "", TabbedView.CSSClass + " ", "")
   
  // ...so then we can append correctly:
  TabbedView.CSSClass = existingClass + "disable-tabs"
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ECFWSecondStep.ButtonCreaEvento()
{
  QappCore.InhibitCdataRenderingHelperQuickValidation = false
   
  Evento e = Eventoinsertionpanel.document
   
  e.clearErrors(999)
  e.DatiPersonalizzati.clearErrors()
  boolean eventoIsValid = e.validate(0, 999)
   
  if (eventoIsValid)
  {
    e.saveToDB(999, false)
    EventoAfterSaveSilentHookFirerer easshf = EventoAfterSaveSilentHookFirerer.create(e, ...)
    string qappsResponses = ""
    easshf.perform(qappsResponses)
    e.setTag("additionalInfo", qappsResponses)
    this.closeEvento(e)
  }
  else 
  {
    ErrorReporter.ShowDocumentErrors(e)
  }
  if (!(e.inserted))
  {
    this.lockForm()
    Eventoinsertionpanel.locked = true
     
    ConfirmationForm.showForm(e, ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ECFWSecondStep.makeAmbitoDropdownReadonlyIfNeeded()
{
  Evento evento = Eventoinsertionpanel.document
  if (evento)
  {
    boolean ammbitoCountIsOne = (EventiAmbitiClasseLinks.getAmbitoCountForClass(evento.IDCLASSE) == 1)
     
    boolean ambitoIsDefined = evento.IDAMBITO > 0
    if (ambitoIsDefined and ammbitoCountIsOne)
    {
      Eventoinsertionpanel.DESCRAMBITOEvento.setEnabled(false)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ECFWSecondStep.makeTipologiaDropdownReadonlyIfneeded()
{
  Evento e = Eventoinsertionpanel.document
  if (e)
  {
    boolean tipologiaCountIsOne = (TipologiaEvento.getTipologiaCountForClass(e.IDCLASSE) == 1)
     
    boolean tipologiaIsDefined = e.IDTIPOLOGIA > 0
    if (tipologiaIsDefined and tipologiaCountIsOne)
    {
      Eventoinsertionpanel.TIPOLOGIAEvento.setEnabled(false)
    }
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
private void ECFWSecondStep.handleResponsabileDropDown()
{
  Evento e = Eventoinsertionpanel.document
   
  e.computeResponsabileWidgetProperties()
  Eventoinsertionpanel.Responsabile.setVisible(e.ResponsibleWidgetVisible)
  Eventoinsertionpanel.Responsabile.setEnabled(!(e.ResponsibleWidgetReadonly))
}


// ──────────────────────────────────

// ********************************************************
// tabbed view content is populated and attached at runtime
// ********************************************************
private void ECFWSecondStep.setupTabs(
  Evento evento // Write a comment for this parameter or press backspace to delete this comment
)
{
  UrlToken ut = UIBusinessLogic.EventoWizardManager.URLToken
  ClasseEvento ce = ClasseEvento.get(evento.IDCLASSE)
  if (ce)
  {
    boolean userIsanonymous = QappCore.Loggeduser.isAnonymous()
    IDCollection mandatoryRefTypes of ReferenceType = evento.getMandatoryRefTypes()
    boolean mandatoryReferenceAvailable = mandatoryRefTypes.count() > 0
     
    // REFERENCES TAB
    boolean showReferenceTab = (ce.SHOWRIFERMENTI == Yes) and !(userIsanonymous) and mandatoryReferenceAvailable
    if (showReferenceTab)
    {
      // add reference tab form
      IDForm ReferenceTabForm = RiferimentiSubform.newInstance(SubForm, ...)
      TabbedView.addForm(ReferenceTabForm)
      this.SubformsArray.addObject(ReferenceTabForm)
       
      // send message to reference tab form to  add reference forms
      ReferenceTabForm.sendMessage("LOAD", evento, ...)
    }
//     
    // CUSTOM DATA TAB
    if (ce.SHOWDATTIP == Yes)
    {
      IDCollection visibileCdataSections of IDDocument = evento.GetAvailableCustomDataSections(QappCore.Loggeduser)
      if (visibileCdataSections.count() > 0)
      {
         // add customdata form
         IDForm CDForm = CustomDataSubform.newInstance(SubForm, ...)
         TabbedView.addForm(CDForm)
          
         evento.setObjectTag("URL_TOKEN", ut)
          
         string shouldRenderOnlyMandatoryCdata = if(ut.CustomDataViewMode == Mandatory, "true", "false")
          
         CDForm.sendMessage("LOAD", evento, shouldRenderOnlyMandatoryCdata, ...)
         this.SubformsArray.addObject(CDForm)
         this.CustomdataSubform = CDForm
      }
    }
     
     
    // DISPOSIZIONI TAB
    boolean showDisposizioniTab = evento.canShowDisposizioniTabInECFW(ut)
    if (showDisposizioniTab and evento.Disposizioni.count() == 1)
    {
      IDForm idf = TabbedView.addFormByIndex(DisposizioneForm.me())
      idf.sendMessage("setDisposizioni", evento, ...)
      this.SubformsArray.addObject(idf)
    }
     
     
    // DOCUMENTI TAB
    if (ut.AllowDocumentsUpload)
    {
      IDForm documentiComunicazioniForm = TabbedView.addFormByIndex(Documenti.me())
      documentiComunicazioniForm.sendMessage("setDocumenti", evento, ...)
      this.SubformsArray.addObject(documentiComunicazioniForm)
    }
     
     
    // INSTRUCTIONS SUBFORM
    if (ut.VisualizzaIstruzioni and evento and evento.INSTRUCTIONS != "" and evento.INSTRUCTIONS != null and OnlyOfficeTools.isOnlyofficeServiceAvailable())
    {
      IDForm instructions = TabbedView.addFormByIndex(InstructionsSubform.me())
      instructions.sendMessage("LOAD", evento, ...)
      this.SubformsArray.addObject(instructions)
    }
  }
}


// ──────────────────────────────────

// ****************************************************************************************************************
// This procedure reads the url token used to access Evento Creation from Web Wizard to assign.
// The visibilities rules on DESCR_TITOLO, ID_TIPOLOGIA and ID_AMBITO fields on the panel "Evento Insertion Panel".
// Then it hides and show the button "Crea Evento" in the upper part or lower part.
// ****************************************************************************************************************
private void ECFWSecondStep.assignVisibilitiesToMainFieldsBasingOnURLToken()
{
  UrlToken ut = UIBusinessLogic.EventoWizardManager.URLToken
  ut.readDataFromInfoContent()
   
  boolean showTitle = ut.HideTitle == false
  boolean showTipologia = ut.HideTipologia == false
  boolean showAmbito = ut.HideAmbito == false
   
  Eventoinsertionpanel.DESCRTITOLO.setVisible(showTitle)
  Eventoinsertionpanel.TIPOLOGIAEvento.setVisible(showTipologia)
  Eventoinsertionpanel.DESCRAMBITOEvento.setVisible(showAmbito)
   
  // button crea evento
  Eventoinsertionpanel.ButtonCreaEventoTop.setVisible(ut.PositionButtonCreaEvento == Up)
  Eventoinsertionpanel.ButtonCreaEventoBottom.setVisible(ut.PositionButtonCreaEvento == Down)
   
  if (ut.DisplayLogo)
  {
    string logoImageFileName = TabParametri.extractPrintLogoToImageFolder("logo")
    Eventoinsertionpanel.imagePlaceholder.loadImage(logoImageFileName)
  }
  else 
  {
    Eventoinsertionpanel.imagePlaceholder.setVisible(false)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ECFWSecondStep.closeEvento(
  Evento evento // 
)
{
  // close evento if URL token parameter is true
  UrlToken ut = UIBusinessLogic.EventoWizardManager.URLToken
  if (ut.ChiusuraAutomatica and (ut.EventoClosureEsito != null and ut.EventoClosureEsito != ""))
  {
    evento.setEventoAsClosed(QappCore.Loggeduser, toInteger(trim(ut.EventoClosureEsito)))
    evento.saveToDB(0, ...)
  }
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ECFWSecondStep.logutbutton()
{
  Tools.performExit(...)
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event DisposizioneForm.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  switch (Message)
  {
    case "setDisposizioni":
      Evento createdEvento = cast(Doc)
       
      if (createdEvento)
      {
         if (!(createdEvento.Disposizioni.loaded))
         {
           createdEvento.loadCollectionFromDB(createdEvento.Disposizioni, ...)
         }
          
         createdEvento.Disposizioni.moveFirst()
          
         Disposizione firstDisp = (Disposizione)createdEvento.Disposizioni.getAt()
          
         if (firstDisp)
         {
           disppanel.setDocument(firstDisp, true)
         }
      }
    break
    case "LOCK":
      disppanel.locked = true
    break
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event Documenti.Load()
{
  DocumentUploadHelper duh = DocumentUploadHelper.create(...)
  this.setObjectTag("documentEdit", duh)
  Uploadpanel.setDocument(duh, true)
   
  this.hasCloseButton = false
  this.hasConfirmButton = false
  Uploadpanel.BlobData.setBlobSize(2000000000, 20000000000, ...)
  Uploadpanel.BlobData.setEnabled(true)
   
  Uploadpanel.locked = false
  Uploadpanel.collapsed = false
   
   
  Documenti.locked = false
  Documenti.setCommandEnabled(FormList, false)
  Documenti.setCommandEnabled(Search, false)
  Documenti.setCommandEnabled(Find, false)
  Documenti.setCommandEnabled(Insert, false)
  Documenti.setCommandEnabled(Delete, false)
  Documenti.setCommandEnabled(Cancel, false)
  Documenti.setCommandEnabled(Refresh, false)
  Documenti.setCommandEnabled(Update, false)
  Documenti.setCommandEnabled(Duplicate, false)
  Documenti.setCommandEnabled(Lookup, false)
  Documenti.setCommandEnabled(EditBlob, false)
  Documenti.setCommandEnabled(DeleteBlob, false)
  Documenti.setCommandEnabled(NewBlob, false)
  Documenti.setCommandEnabled(SaveBlob, false)
  Documenti.setCommandEnabled(PrintBook, false)
  Documenti.setCommandEnabled(Attach, false)
  Documenti.setCommandEnabled(Export, false)
  Documenti.setCommandEnabled(Navigate, false)
  Documenti.setCommandEnabled(GroupPanel, false)
  Documenti.collapsable = false
  Documenti.caption = ""
   
}


// ──────────────────────────────────

// ************************************************************************
// Event raised when a form sends a message using the SendMessage procedure
// ************************************************************************
event Documenti.OnSendMessage(
  string Message // Indicates the name of the message
  IDForm Sender  // Identifies the form that sent the message. IDForm type object.
  IDDocument Doc // Optional. Document associated with the message.
  string Par1    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par2    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par3    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
  string Par4    // Optional. Parameter associated with the message; can be of any type (except object or generic document).
)
{
  if (Message == "setDocumenti")
  {
    this.Evento = (Evento)Doc
    Documenti.setCollection(this.Evento.ModuleDocuments, ...)
  }
  else if (Message == "LOCK")
  {
    Documenti.locked = true
    Documenti.remove.setEnabled(false)
  }
  else if (Message == "CATCHME")
  {
  }
}


// ──────────────────────────────────

// **************************************************************************************************************************
// Event raised by the panel after saving the file uploaded by the user to the database or deleting the contents of the blob.
// **************************************************************************************************************************
event Documenti.Uploadpanel.AfterBLOBUpdate(
  int Column       // An integer specifying which panel field is involved in the update or delete operation. It should be compared with the Me function of the panel fields.
  int Size         // Size of the uploaded file in bytes, or -1 if the contents of the blob have been deleted.
  string Extension // A string containing the extension of the file being loaded.
)
{
  DocumentUploadHelper duh = this.getObjectTag("documentEdit")
   
   
  if (duh)
  {
    duh.Description = this.SelectedDocumentName
    duh.setExtension(Extension)
    this.confirmUpload()
     
    if (duh and duh.ResultingFilePath != "" and duh.ResultingFilePath != null)
    {
      this.Evento.addDocComunicazioniFromFile(duh.ResultingFilePath, duh.Description, QappCore.Loggeduser, ..., true)
    }
  }
}


// ──────────────────────────────────

// ********************************************************************************************
// Event raised by the panel before recording a blob just uploaded by the user in the database.
// ********************************************************************************************
event Documenti.Uploadpanel.BeforeBLOBUpdate(
  inout boolean Cancel // If set to True, the file will not be uploaded or deleted.
  int Column           // An integer identifying the panel field where the file is being uploaded. It should be compared with the Me property of the panel fields.
  int Size             // The size of the uploaded file in bytes; if deleting, the value is -1. This can be used to determine which operation is in progress for the blob field.
  string Extension     // A string containing the extension of the file being loaded. For example, "doc" for Word files.
  string FilePath      // A string that contains the name of the file uploaded to the server, including the extension. This file is stored in the TEMP subdirectory of the web application.
)
{
  this.SelectedDocumentName = FilePath
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void Documenti.confirmUpload()
{
  boolean result = false
  DocumentUploadHelper d = Uploadpanel.document
   
  if (d)
  {
    if (d.BlobData != null)
    {
      d.computeBlob()
      result = true
    }
    else 
    {
    }
  }
}


// ──────────────────────────────────

// **************
// remove the row
// **************
public void Documenti.remove()
{
  ModuleDocument md = Documenti.document
  if (md)
  {
    md.deleted = true
    Evento.ModuleDocuments.removeDeleted()
  }
}


// ──────────────────────────────────

// ***********************************************
// Event raised to the form when loading in memory
// ***********************************************
event ConfirmationForm.Load()
{
  Buttonok.enabled = false
  X.executeOnClient("hideMainHeader();")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ConfirmationForm.showForm(
  Evento evento                                                                                             // Write a comment for this parameter or press backspace to delete this comment
  optional string:eventoFromWebConfirmationFormDisplayModes displayMode = "confirmationAfterEventoCreation" // 
)
{
   
  string retrieveGUIDDescription = UIBusinessLogic.URLTOKEN.GUIDInfoDescription
   
  ModelloEvento me = evento.getModelloEvento()
  boolean modelloSupportsPublicStatus = me.SUPPORTPUBLICINFO == Yes
  EventoPublicInfo evapublicinfo = null
  if (modelloSupportsPublicStatus)
  {
    evapublicinfo = evento.getEventoPublicInfo()
    boolean publicStatusExists = evapublicinfo != null
     
    // this condition in principle never fires anyway we keep it for protecting us from an exotic situation in which publicInfo is not generted ven if modello supports publicStatus
    if (!(publicStatusExists))
    {
      throw 1, "Problema con PublicInfo, contattare un amministratore"
    }
    string retrievedGUID = evapublicinfo.GUID
    this.EventoPublicInfo = evapublicinfo
     
    this.GUID = retrievedGUID
    retrieveGUIDDescription = replace(retrieveGUIDDescription, "[GUID]", this.GUID)
    Confirmationpanel.LabelGUIDinfo.text = retrieveGUIDDescription
     
    Buttonok.visible = false
  }
  else 
  {
    Buttonok.enabled = true
     
    // hide the fields that make sense only for Public info
    Confirmationpanel.LabelGUIDinfo.setVisible(false)
    ButtonCopyCode.visible = false
    ButtonCopyUrl.visible = false
    this.height = this.height - 200
  }
   
  string mainTitle = ""
  string mainDescription = ""
  if (displayMode == confirmationAfterEventoCreation)
  {
    string retrievedDescription = UIBusinessLogic.URLTOKEN.ConfirmationEventoCreatedDescription
    retrievedDescription = replace(retrievedDescription, "[NRO_EVENTO]", "|1")
    retrievedDescription = formatMessage(retrievedDescription, evento.NROEVENTO, ...)
     
     
    // we retrieve the message provided from the afterSave hooks called after creating the evento
    string additionalInfoFromQapp = evento.getTag("additionalInfo")
    mainDescription = retrievedDescription + " " + additionalInfoFromQapp
     
    string retrievedTitle = UIBusinessLogic.URLTOKEN.ConfirmationMessageTitle
     
    mainTitle = retrievedTitle
  }
  else 
  {
    mainDescription = this.EventoPublicInfo.getDescriptionTextForPublicInfoEventoForm()
    mainTitle = "Dettaglio Informazioni Pubbliche"
    Confirmationpanel.LabelGUIDinfo.setVisible(false)
    Buttonok.visible = false
     
    // close all other form (tipically there could be URL token form opened in the same session)
    UICommonUtils.closeAllFormsButOne(this.IDForm())
    UICommonUtils.makeModalFormWithDarkBackground()
    this.bringToFront()
  }
  UIBusinessLogic.widgetMode = true
  this.caption = mainTitle
  Confirmationpanel.Labelconfirmationevento.text = mainDescription
   
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ConfirmationForm.Buttonok()
{
  this.close(true)
   
  string redirectUrl = UIBusinessLogic.URLTOKEN.RedirectUrlAfterEventoInsertion
   
  if (redirectUrl != "")
    UIBusinessLogic.DisconnectTimerUrl = redirectUrl
  else 
    UIBusinessLogic.DisconnectTimerUrl = "???"
   
  DisconnectTimer.enabled = true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ConfirmationForm.ButtonCopyGuid()
{
  AppTools.copyStringToClipboard(this.EventoPublicInfo.GUID)
   
  Buttonok.enabled = true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void ConfirmationForm.ButtonCopyUrl()
{
  string completeUrl = this.EventoPublicInfo.getUrl()
   
  AppTools.copyStringToClipboard(completeUrl)
   
  Buttonok.enabled = true
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UIBusinessLogic.DisconnectTimer()
{
  DisconnectTimer.enabled = false
  Tools.performExit(UIBusinessLogic.DisconnectTimerUrl)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UIBusinessLogic.CloseSession()
{
  Tools.performExit(...)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UIBusinessLogic.RestartSessionTimer()
{
  string url = UIBusinessLogic.RestartSessionUrl
   
  // not needed sine it is a 1 tick timer, anyway we leave this for stressing it is a one off timer
  RestartSessionTimer.enabled = false
   
  Tools.performExit(url)
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UIBusinessLogic.setLoginMessageForStaticMethods(
  string message // 
)
{
  UIBusinessLogic.setLoginMessage(message, ...)
   
  DevTools.ToBeReviewed("setLoginMessage does not compile if called in a class static method, such as OnCommandHandler, so this method hads been created as a trick to avoid problems, it is all fine")
}


// ──────────────────────────────────

// ****************************************
// Describe what this procedure is used for
// ****************************************
public void UIBusinessLogic.storeQualibusWebUrlInDatabaseIfNeeded(
  optional boolean silent = 0 // 
)
{
  string qualibusWebUrl = X.GetApplicationUrl(...)
   
  TabParametri tp = TabParametri.getInstance()
   
  if (tp.QUALIBUSWEBBASEURL == "")
  {
    tp.QUALIBUSWEBBASEURL = qualibusWebUrl
    tp.saveToDB(...)
    QappCore.setLoginMessageForNextSession("Qualibus web correctly initialized")
  }
  else 
  {
    QappCore.setLoginMessageForNextSession("Qualibus web was already initialized, to change the URL edit the data on the database")
  }
  Tools.performExit(...)
}
